Autopsy  4.21.0
Graphical digital forensics platform for The Sleuth Kit and other tools.
Chromium.java
Go to the documentation of this file.
1 /*
2  *
3  * Autopsy Forensic Browser
4  *
5  * Copyright 2012-2021 Basis Technology Corp.
6  *
7  * Copyright 2012 42six Solutions.
8  *
9  * Project Contact/Architect: carrier <at> sleuthkit <dot> org
10  *
11  * Licensed under the Apache License, Version 2.0 (the "License");
12  * you may not use this file except in compliance with the License.
13  * You may obtain a copy of the License at
14  *
15  * http://www.apache.org/licenses/LICENSE-2.0
16  *
17  * Unless required by applicable law or agreed to in writing, software
18  * distributed under the License is distributed on an "AS IS" BASIS,
19  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
20  * See the License for the specific language governing permissions and
21  * limitations under the License.
22  */
23 package org.sleuthkit.autopsy.recentactivity;
24 
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 java.io.BufferedReader;
33 import org.openide.util.NbBundle;
35 import java.util.logging.Level;
36 import java.io.File;
37 import java.io.FileNotFoundException;
38 import java.io.FileReader;
39 import java.io.IOException;
40 import java.util.Collection;
41 import java.util.List;
42 import java.util.Map;
43 import java.util.HashMap;
44 import java.util.ArrayList;
45 import java.util.Arrays;
46 import java.util.Set;
47 import org.apache.commons.io.FilenameUtils;
48 import org.apache.commons.lang3.StringUtils;
49 import org.openide.util.NbBundle.Messages;
69 
73 class Chromium extends Extract {
74 
75  private static final String HISTORY_QUERY = "SELECT urls.url, urls.title, urls.visit_count, urls.typed_count, " //NON-NLS
76  + "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"; //NON-NLS
77  private static final String COOKIE_QUERY = "SELECT name, value, host_key, expires_utc,last_access_utc, creation_utc FROM cookies"; //NON-NLS
78  private static final String DOWNLOAD_QUERY = "SELECT full_path, url, start_time, received_bytes FROM downloads"; //NON-NLS
79  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"; //NON-NLS
80  private static final String LOGIN_QUERY = "SELECT origin_url, username_value, date_created, signon_realm from logins"; //NON-NLS
81  private static final String AUTOFILL_QUERY = "SELECT name, value, count, date_created "
82  + " FROM autofill, autofill_dates "
83  + " WHERE autofill.pair_id = autofill_dates.pair_id"; //NON-NLS
84  private static final String AUTOFILL_QUERY_V8X = "SELECT name, value, count, date_created, date_last_used from autofill"; //NON-NLS
85  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 "
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 
89  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"
90  + " FROM autofill_profiles, autofill_profile_names, autofill_profile_emails, autofill_profile_phones"
91  + " WHERE autofill_profiles.guid = autofill_profile_names.guid AND autofill_profiles.guid = autofill_profile_emails.guid AND autofill_profiles.guid = autofill_profile_phones.guid";
92  private static final String FAVICON_QUERY = "SELECT page_url, last_updated, last_requested FROM icon_mapping, favicon_bitmaps "
93  + " WHERE icon_mapping.icon_id = favicon_bitmaps.icon_id";
94  private static final String LOCALSTATE_FILE_NAME = "Local State";
95  private static final String EXTENSIONS_FILE_NAME = "Secure Preferences";
96  private static final String HISTORY_FILE_NAME = "History";
97  private static final String BOOKMARK_FILE_NAME = "Bookmarks";
98  private static final String COOKIE_FILE_NAME = "Cookies";
99  private static final String LOGIN_DATA_FILE_NAME = "Login Data";
100  private static final String WEB_DATA_FILE_NAME = "Web Data";
101  private static final String FAVICON_DATA_FILE_NAME = "Favicons";
102  private static final String UC_BROWSER_NAME = "UC Browser";
103  private static final String OPERA_BROWSER_NAME = "Opera";
104  private static final String ENCRYPTED_FIELD_MESSAGE = "The data was encrypted.";
105  private static final String GOOGLE_PROFILE_NAME = "Profile";
106  private static final String GOOGLE_PROFILE = "Google Chrome ";
107  private static final String FAVICON_ARTIFACT_NAME = "TSK_FAVICON"; //NON-NLS
108  private static final String LOCAL_STATE_ARTIFACT_NAME = "TSK_LOCAL_STATE"; //NON-NLS
109  private static final String EXTENSIONS_ARTIFACT_NAME = "TSK_CHROME_EXTENSIONS"; //NON-NLS
110  private static final String MALICIOUS_EXTENSION_FOUND = "Malicious Extension Found - ";
111 
112  private Boolean databaseEncrypted = false;
113  private Boolean fieldEncrypted = false;
114 
115  private static final String MALICIOUS_CHROME_EXTENSION_LIST = "malicious_chrome_extensions.csv";
116  private Map<String, String> maliciousChromeExtensions;
117 
118  private final Logger logger = Logger.getLogger(this.getClass().getName());
119  private Content dataSource;
120  private final IngestJobContext context;
121 
122  private Map<String, String> userProfiles;
123  private Map<String, String> browserLocations;
124 
125  private static final Map<String, String> BROWSERS_MAP = ImmutableMap.<String, String>builder()
126  .put("Microsoft Edge", "Microsoft/Edge/User Data")
127  .put("Yandex", "YandexBrowser/User Data")
128  .put("Opera", "Opera Software/Opera Stable")
129  .put("SalamWeb", "SalamWeb/User Data")
130  .put("UC Browser", "UCBrowser/User Data%")
131  .put("Brave", "BraveSoftware/Brave-Browser/User Data")
132  .put("Google Chrome", "Chrome/User Data")
133  .build();
134 
135  @Messages({"# {0} - browserName",
136  "Progress_Message_Chrome_History=Chrome History Browser {0}",
137  "# {0} - browserName",
138  "Progress_Message_Chrome_Bookmarks=Chrome Bookmarks Browser {0}",
139  "# {0} - browserName",
140  "Progress_Message_Chrome_Cookies=Chrome Cookies Browser {0}",
141  "# {0} - browserName",
142  "Progress_Message_Chrome_Downloads=Chrome Downloads Browser {0}",
143  "Progress_Message_Chrome_Profiles=Chrome Profiles {0}",
144  "Progress_Message_Chrome_Extensions=Chrome Extensions {0}",
145  "Progress_Message_Chrome_Favicons=Chrome Downloads Favicons {0}",
146  "Progress_Message_Chrome_FormHistory=Chrome Form History",
147  "# {0} - browserName",
148  "Progress_Message_Chrome_AutoFill=Chrome Auto Fill Browser {0}",
149  "# {0} - browserName",
150  "Progress_Message_Chrome_Logins=Chrome Logins Browser {0}",
151  "Progress_Message_Chrome_Cache=Chrome Cache",})
152 
153  Chromium(IngestJobContext context) {
154  super(NbBundle.getMessage(Chromium.class, "Chrome.moduleName"), context);
155  this.context = context;
156  }
157 
158  @Override
159  public void process(Content dataSource, DataSourceIngestModuleProgress progressBar) {
160  this.dataSource = dataSource;
161  dataFound = false;
162  long ingestJobId = context.getJobId();
163  String now1 = "";
164  loadMaliciousChromeExetnsions();
165  userProfiles = new HashMap<>();
166  browserLocations = new HashMap<>();
167  for (Map.Entry<String, String> browser : BROWSERS_MAP.entrySet()) {
168  progressBar.progress(NbBundle.getMessage(this.getClass(), "Progress_Message_Chrome_Profiles", browser.getKey()));
169  getProfiles(browser.getKey(), browser.getValue(), ingestJobId);
170  if (context.dataSourceIngestIsCancelled()) {
171  return;
172  }
173  }
174  for (Map.Entry<String, String> profile : userProfiles.entrySet()) {
175  String browserLocation = profile.getKey();
176  String browserName = browserLocations.get(browserLocation);
177  String userName = profile.getValue();
178  progressBar.progress(NbBundle.getMessage(this.getClass(), "Progress_Message_Chrome_Extensions", browserName));
179  this.getExtensions(browserName, browserLocation, userName, ingestJobId);
180  if (context.dataSourceIngestIsCancelled()) {
181  return;
182  }
183  progressBar.progress(NbBundle.getMessage(this.getClass(), "Progress_Message_Chrome_History", browserName));
184  this.getHistory(browserName, browserLocation, userName, ingestJobId);
185  if (context.dataSourceIngestIsCancelled()) {
186  return;
187  }
188 
189  progressBar.progress(NbBundle.getMessage(this.getClass(), "Progress_Message_Chrome_Bookmarks", browserName));
190  this.getBookmark(browserName, browserLocation, userName, ingestJobId);
191  if (context.dataSourceIngestIsCancelled()) {
192  return;
193  }
194 
195  progressBar.progress(NbBundle.getMessage(this.getClass(), "Progress_Message_Chrome_Cookies", browserName));
196  this.getCookie(browserName, browserLocation, userName, ingestJobId);
197  if (context.dataSourceIngestIsCancelled()) {
198  return;
199  }
200 
201  progressBar.progress(NbBundle.getMessage(this.getClass(), "Progress_Message_Chrome_Logins", browserName));
202  this.getLogins(browserName, browserLocation, userName, ingestJobId);
203  if (context.dataSourceIngestIsCancelled()) {
204  return;
205  }
206 
207  progressBar.progress(NbBundle.getMessage(this.getClass(), "Progress_Message_Chrome_AutoFill", browserName));
208  this.getAutofill(browserName, browserLocation, userName, ingestJobId);
209  if (context.dataSourceIngestIsCancelled()) {
210  return;
211  }
212 
213  progressBar.progress(NbBundle.getMessage(this.getClass(), "Progress_Message_Chrome_Downloads", browserName));
214  this.getDownload(browserName, browserLocation, userName, ingestJobId);
215  if (context.dataSourceIngestIsCancelled()) {
216  return;
217  }
218 
219  progressBar.progress(NbBundle.getMessage(this.getClass(), "Progress_Message_Chrome_Favicons", browserName));
220  this.getFavicons(browserName, browserLocation, userName, ingestJobId);
221  if (context.dataSourceIngestIsCancelled()) {
222  return;
223  }
224  }
225 
226  progressBar.progress(Bundle.Progress_Message_Chrome_Cache());
227  ChromeCacheExtractor chromeCacheExtractor = new ChromeCacheExtractor(dataSource, context, progressBar);
228  chromeCacheExtractor.processCaches();
229  }
230 
238  private void getProfiles(String browser, String browserLocation, long ingestJobId) {
239  FileManager fileManager = currentCase.getServices().getFileManager();
240  String browserName = browser;
241  List<AbstractFile> localStateFiles;
242  String localStateName = LOCALSTATE_FILE_NAME;
243  if (browserName.equals(UC_BROWSER_NAME)) {
244  localStateName = LOCALSTATE_FILE_NAME + "%";
245  }
246  try {
247  localStateFiles = fileManager.findFiles(dataSource, localStateName, browserLocation); //NON-NLS
248  } catch (TskCoreException ex) {
249  String msg = NbBundle.getMessage(this.getClass(), "Chrome.getLocalState.errMsg.errGettingFiles");
250  logger.log(Level.SEVERE, msg, ex);
251  this.addErrorMessage(this.getDisplayName() + ": " + msg);
252  return;
253  }
254 
255  // get only the allocated ones, for now
256  List<AbstractFile> allocatedLocalStateFiles = new ArrayList<>();
257  for (AbstractFile localStateFile : localStateFiles) {
258  if (localStateFile.isMetaFlagSet(TskData.TSK_FS_META_FLAG_ENUM.ALLOC)) {
259  allocatedLocalStateFiles.add(localStateFile);
260  }
261  }
262 
263  // log a message if we don't have any allocated Local State files
264  if (allocatedLocalStateFiles.isEmpty()) {
265  String msg = NbBundle.getMessage(this.getClass(), "Chrome.getLocalState.errMsg.couldntFindAnyFiles");
266  logger.log(Level.INFO, msg);
267  return;
268  }
269 
270  dataFound = true;
271  Collection<BlackboardArtifact> bbartifacts = new ArrayList<>();
272  int j = 0;
273  while (j < allocatedLocalStateFiles.size()) {
274  if (browser.contains(GOOGLE_PROFILE_NAME)) {
275  String parentPath = FilenameUtils.normalizeNoEndSeparator(allocatedLocalStateFiles.get(j).getParentPath());
276  browserName = GOOGLE_PROFILE + " " + FilenameUtils.getBaseName(parentPath);
277  }
278  String temps = RAImageIngestModule.getRATempPath(currentCase, browserName, ingestJobId) + File.separator + allocatedLocalStateFiles.get(j).getName() + j; //NON-NLS
279  final AbstractFile localStateFile = allocatedLocalStateFiles.get(j++);
280  if ((localStateFile.getSize() == 0) || (localStateFile.getName().toLowerCase().contains("-slack"))
281  || (localStateFile.getName().toLowerCase().contains("cache")) || (localStateFile.getName().toLowerCase().contains("media"))
282  || (localStateFile.getName().toLowerCase().contains("index"))) {
283  continue;
284  }
285  try {
286  ContentUtils.writeToFile(localStateFile, new File(temps), context::dataSourceIngestIsCancelled);
287  } catch (ReadContentInputStreamException ex) {
288  logger.log(Level.WARNING, String.format("Error reading Chrome web Local State artifacts file '%s' (id=%d).",
289  localStateFile.getName(), localStateFile.getId()), ex); //NON-NLS
290  this.addErrorMessage(NbBundle.getMessage(this.getClass(), "Chrome.getLocalState.errMsg.errAnalyzingFile",
291  this.getDisplayName(), localStateFile.getName()));
292  continue;
293  } catch (IOException ex) {
294  logger.log(Level.SEVERE, String.format("Error writing temp file '%s' for Chrome Local State artifacts file '%s' (id=%d).",
295  temps, localStateFile.getName(), localStateFile.getId()), ex); //NON-NLS
296  this.addErrorMessage(NbBundle.getMessage(this.getClass(), "Chrome.getLocalState.errMsg.errAnalyzingFile",
297  this.getDisplayName(), localStateFile.getName()));
298  continue;
299  }
300 
301  if (context.dataSourceIngestIsCancelled()) {
302  break;
303  }
304 
305  FileReader tempReader;
306  try {
307  tempReader = new FileReader(temps);
308  } catch (FileNotFoundException ex) {
309  logger.log(Level.WARNING, "Error while trying to read into the LocalState file.", ex); //NON-NLS
310  continue;
311  }
312 
313  JsonElement jsonElement;
314  JsonObject jElement, jProfile, jInfoCache;
315 
316  try {
317  jsonElement = JsonParser.parseReader(tempReader);
318  jElement = jsonElement.getAsJsonObject();
319  if (jElement.has("profile")) {
320  jProfile = jElement.get("profile").getAsJsonObject(); //NON-NLS
321  jInfoCache = jProfile.get("info_cache").getAsJsonObject();
322  } else {
323  userProfiles.put(browserLocation, "Default");
324  browserLocations.put(browserLocation, browser);
325  continue;
326  }
327  } catch (JsonIOException | JsonSyntaxException | IllegalStateException ex) {
328  logger.log(Level.WARNING, "Error parsing Json from LocalState.", ex); //NON-NLS
329  this.addErrorMessage(NbBundle.getMessage(this.getClass(), "Chrome.getlocalState.errMsg.errAnalyzingFile",
330  this.getDisplayName(), localStateFile.getName()));
331  continue;
332  }
333 
334  BlackboardArtifact.Type localStateArtifactType;
335 
336  try {
337  localStateArtifactType = createArtifactType(LOCAL_STATE_ARTIFACT_NAME, NbBundle.getMessage(this.getClass(), "Chrome.getLocalState.displayName"));
338  } catch (TskCoreException ex) {
339  logger.log(Level.SEVERE, String.format("Error creating artifact type for LocalState."), ex); //NON-NLS
340  this.addErrorMessage(NbBundle.getMessage(this.getClass(), "Chrome.getfavicon.errMsg.errCreateArtifact"));
341  continue;
342 
343  }
344  Set<String> profileNames = jInfoCache.keySet();
345  for (String profileName : profileNames) {
346  JsonElement result = jInfoCache.get(profileName);
347  JsonObject profile = result.getAsJsonObject();
348  if (profile == null) {
349  continue;
350  }
351  JsonElement gaiaIdEl = profile.get("gaia_id"); //NON-NLS
352  String gaiaId;
353  if (gaiaIdEl != null) {
354  gaiaId = gaiaIdEl.getAsString();
355  } else {
356  gaiaId = "";
357  }
358  String hostedDomain;
359  JsonElement hostedDomainEl = profile.get("hosted_domain"); //NON-NLS
360  if (hostedDomainEl != null) {
361  hostedDomain = hostedDomainEl.getAsString();
362  } else {
363  hostedDomain= "";
364  }
365  String shortcutName;
366  JsonElement shortcutNameEl = profile.get("shortcut_name"); //NON-NLS
367  if (shortcutNameEl != null) {
368  shortcutName = shortcutNameEl.getAsString();
369  } else {
370  shortcutName = "";
371  }
372  String name;
373  JsonElement nameEl = profile.get("name"); //NON-NLS
374  if (nameEl != null) {
375  name = nameEl.getAsString();
376  } else {
377  name= "";
378  }
379  String userName;
380  JsonElement userNameEl = profile.get("user_name"); //NON-NLS
381  if (userNameEl != null) {
382  userName = userNameEl.getAsString();
383  } else {
384  userName = "";
385  }
386 
387  if (userName.contains("")) {
388  userProfiles.put(browserLocation + "/" + profileName, name);
389  browserLocations.put(browserLocation + "/" + profileName, browser);
390  } else {
391  userProfiles.put(browserLocation + "/" + profileName, userName);
392  browserLocations.put(browserLocation + "/" + profileName, browser);
393  }
394 
395  Collection<BlackboardAttribute> bbattributes = new ArrayList<>();
396  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_PATH,
397  RecentActivityExtracterModuleFactory.getModuleName(), profileName));
398  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_USER_ID,
399  RecentActivityExtracterModuleFactory.getModuleName(), gaiaId));
400  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DOMAIN,
401  RecentActivityExtracterModuleFactory.getModuleName(), hostedDomain));
402  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_SHORTCUT,
403  RecentActivityExtracterModuleFactory.getModuleName(), shortcutName));
404  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_NAME,
405  RecentActivityExtracterModuleFactory.getModuleName(), name));
406  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_USER_NAME,
407  RecentActivityExtracterModuleFactory.getModuleName(), userName));
408  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_PROG_NAME,
409  RecentActivityExtracterModuleFactory.getModuleName(), browserName));
410 
411  try {
412  bbartifacts.add(createArtifactWithAttributes(localStateArtifactType, localStateFile, bbattributes));
413  } catch (TskCoreException ex) {
414  logger.log(Level.SEVERE, String.format("Failed to create bookmark artifact for file (%d)", localStateFile.getId()), ex);
415  }
416 
417  }
418 
419  if (!context.dataSourceIngestIsCancelled()) {
420  postArtifacts(bbartifacts);
421  }
422  bbartifacts.clear();
423 
424  }
425  // Check if Default, Guest Profile and System Profile are in the usersProfiles, if they are not then add them
426  if (!userProfiles.containsKey("Default")) {
427  userProfiles.put(browserLocation + "/" + "Default", "Default");
428  browserLocations.put(browserLocation + "/" + "Default", browser);
429  }
430  if (!userProfiles.containsKey("Guest Profile")) {
431  userProfiles.put(browserLocation + "/" + "Guest Profile", "Guest");
432  browserLocations.put(browserLocation + "/" + "Guest Profile", browser);
433  }
434  if (!userProfiles.containsKey("System Profile")) {
435  userProfiles.put(browserLocation + "/" + "System Profile", "System");
436  browserLocations.put(browserLocation + "/" + "System Profile", browser);
437  }
438  }
439 
447  private void getExtensions(String browser, String browserLocation, String userName, long ingestJobId) {
448  FileManager fileManager = currentCase.getServices().getFileManager();
449  String browserName = browser;
450  List<AbstractFile> extensionFiles;
451  String extensionsName = EXTENSIONS_FILE_NAME;
452  if (browserName.equals(UC_BROWSER_NAME)) {
453  extensionsName = EXTENSIONS_FILE_NAME + "%";
454  }
455  try {
456  // Local State file is found in the directory about the browserLocation, that is why it is being removed
457  extensionFiles = fileManager.findFiles(dataSource, extensionsName, browserLocation); //NON-NLS
458  } catch (TskCoreException ex) {
459  String msg = NbBundle.getMessage(this.getClass(), "Chrome.getExtensions.errMsg.errGettingFiles");
460  logger.log(Level.SEVERE, msg, ex);
461  this.addErrorMessage(this.getDisplayName() + ": " + msg);
462  return;
463  }
464 
465  // get only the allocated ones, for now
466  List<AbstractFile> allocatedExtensionsFiles = new ArrayList<>();
467  for (AbstractFile extensionFile : extensionFiles) {
468  if (extensionFile.isMetaFlagSet(TskData.TSK_FS_META_FLAG_ENUM.ALLOC)) {
469  allocatedExtensionsFiles.add(extensionFile);
470  }
471  }
472 
473  // log a message if we don't have any allocated Local State files
474  if (allocatedExtensionsFiles.isEmpty()) {
475  String msg = NbBundle.getMessage(this.getClass(), "Chrome.getExtensions.errMsg.couldntFindAnyFiles");
476  logger.log(Level.INFO, msg);
477  return;
478  }
479 
480  dataFound = true;
481  Collection<BlackboardArtifact> bbartifacts = new ArrayList<>();
482  int j = 0;
483  while (j < allocatedExtensionsFiles.size()) {
484  if (browser.contains(GOOGLE_PROFILE_NAME)) {
485  String parentPath = FilenameUtils.normalizeNoEndSeparator(allocatedExtensionsFiles.get(j).getParentPath());
486  browserName = GOOGLE_PROFILE + " " + FilenameUtils.getBaseName(parentPath);
487  }
488  String temps = RAImageIngestModule.getRATempPath(currentCase, browserName, ingestJobId) + File.separator + allocatedExtensionsFiles.get(j).getName() + j; //NON-NLS
489  final AbstractFile extensionFile = allocatedExtensionsFiles.get(j++);
490  if ((extensionFile.getSize() == 0) || (extensionFile.getName().toLowerCase().contains("-slack"))
491  || (extensionFile.getName().toLowerCase().contains("cache")) || (extensionFile.getName().toLowerCase().contains("media"))
492  || (extensionFile.getName().toLowerCase().contains("index"))) {
493  continue;
494  }
495  try {
496  ContentUtils.writeToFile(extensionFile, new File(temps), context::dataSourceIngestIsCancelled);
497  } catch (ReadContentInputStreamException ex) {
498  logger.log(Level.WARNING, String.format("Error reading Chrome web extension artifacts file '%s' (id=%d).",
499  extensionFile.getName(), extensionFile.getId()), ex); //NON-NLS
500  this.addErrorMessage(NbBundle.getMessage(this.getClass(), "Chrome.getExtensions.errMsg.errAnalyzingFile",
501  this.getDisplayName(), extensionFile.getName()));
502  continue;
503  } catch (IOException ex) {
504  logger.log(Level.SEVERE, String.format("Error writing temp file '%s' for Chrome Extensions artifacts file '%s' (id=%d).",
505  temps, extensionFile.getName(), extensionFile.getId()), ex); //NON-NLS
506  this.addErrorMessage(NbBundle.getMessage(this.getClass(), "Chrome.getExtensions.errMsg.errAnalyzingFile",
507  this.getDisplayName(), extensionFile.getName()));
508  continue;
509  }
510 
511  if (context.dataSourceIngestIsCancelled()) {
512  break;
513  }
514 
515  FileReader tempReader;
516  try {
517  tempReader = new FileReader(temps);
518  } catch (FileNotFoundException ex) {
519  logger.log(Level.WARNING, "Error while trying to read into the Secure Preferences file.", ex); //NON-NLS
520  continue;
521  }
522 
523  BlackboardArtifact.Type localStateArtifactType;
524 
525  try {
526  localStateArtifactType = createArtifactType(EXTENSIONS_ARTIFACT_NAME, NbBundle.getMessage(this.getClass(), "Chrome.getExtensions.displayName"));
527  } catch (TskCoreException ex) {
528  logger.log(Level.SEVERE, String.format("Error creating artifact type for Secure Preferences."), ex); //NON-NLS
529  this.addErrorMessage(NbBundle.getMessage(this.getClass(), "Chrome.getExtensions.errMsg.errCreateArtifact"));
530  continue;
531  }
532 
533  String profileName = FilenameUtils.getBaseName(StringUtils.chop(extensionFile.getParentPath()));
534 
535  JsonElement jsonElement;
536  JsonObject jElement, jExtensions, jSettings;
537 
538  try {
539  jsonElement = JsonParser.parseReader(tempReader);
540  jElement = jsonElement.getAsJsonObject();
541  if (jElement.has("extensions")) {
542  logger.log(Level.WARNING, String.format("Processing Secure Preferences from %s", extensionFile.getParentPath()));
543  jExtensions = jElement.get("extensions").getAsJsonObject(); //NON-NLS
544  if (!browserName.equals(OPERA_BROWSER_NAME)) {
545  jSettings = jExtensions.get("settings").getAsJsonObject();
546  } else {
547  jSettings = jExtensions.get("opsettings").getAsJsonObject();
548  }
549  } else {
550  continue;
551  }
552  } catch (JsonIOException | JsonSyntaxException | IllegalStateException ex) {
553  logger.log(Level.WARNING, "Error parsing Json from Secure Preferences.", ex); //NON-NLS
554  this.addErrorMessage(NbBundle.getMessage(this.getClass(), "Chrome.getExtensoins.errMsg.errAnalyzingFile",
555  this.getDisplayName(), extensionFile.getName()));
556  continue;
557  }
558 
559  Set<String> extensions = jSettings.keySet();
560  for (String extension : extensions) {
561  JsonElement result = jSettings.get(extension);
562  JsonObject ext = result.getAsJsonObject();
563  if (ext == null) {
564  continue;
565  }
566  JsonElement flagEl = ext.get("state"); //NON-NLS
567  String flag;
568  if (flagEl != null) {
569  if (flagEl.getAsInt() == 1) {
570  flag = "Enabled";
571  } else {
572  flag = "Disabled";
573  }
574  } else {
575  flag = "";
576  }
577  String apiGrantedPermissions = "";
578  if (ext.has("active_permissions")) {
579  JsonObject permissions = ext.get("active_permissions").getAsJsonObject();
580  JsonArray apiPermissions = permissions.get("api").getAsJsonArray();
581  for (JsonElement apiPermission : apiPermissions) {
582  if (apiPermission.isJsonPrimitive()) {
583  String apigrantEl = apiPermission.getAsString();
584  if (apigrantEl != null) {
585  apiGrantedPermissions = apiGrantedPermissions + ", " + apigrantEl;
586  } else {
587  apiGrantedPermissions = apiGrantedPermissions + "";
588  }
589  }
590  }
591  }
592  String version;
593  String description;
594  String extName;
595  if (ext.has("manifest")) {
596  JsonObject manifest = ext.get("manifest").getAsJsonObject();
597  JsonElement descriptionEl = manifest.get("description");
598  if (descriptionEl != null) {
599  description = descriptionEl.getAsString();
600  } else {
601  description = "";
602  }
603  JsonElement versionEl = manifest.get("version");
604  if (versionEl != null) {
605  version = versionEl.getAsString();
606  } else {
607  version = "";
608  }
609  JsonElement extNameEl = manifest.get("name");
610  if (extNameEl != null) {
611  extName = extNameEl.getAsString();
612  } else {
613  extName = "";
614  }
615  } else {
616  version = "";
617  description = "";
618  extName = "";
619  }
620  BlackboardArtifact art = null;
621  Collection<BlackboardAttribute> bbattributes = new ArrayList<>();
622  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_ID,
623  RecentActivityExtracterModuleFactory.getModuleName(), extension));
624  if (maliciousChromeExtensions.get(extension) != null) {
625  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_COMMENT,
626  RecentActivityExtracterModuleFactory.getModuleName(),
627  MALICIOUS_EXTENSION_FOUND + maliciousChromeExtensions.getOrDefault(extension, "No Source Identified")));
628  }
629  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_NAME,
630  RecentActivityExtracterModuleFactory.getModuleName(), extName));
631  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DESCRIPTION,
632  RecentActivityExtracterModuleFactory.getModuleName(), description));
633  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_VERSION,
634  RecentActivityExtracterModuleFactory.getModuleName(), version));
635  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_FLAG,
636  RecentActivityExtracterModuleFactory.getModuleName(), flag));
637  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_PERMISSIONS,
638  RecentActivityExtracterModuleFactory.getModuleName(), apiGrantedPermissions.replaceFirst(", ", "")));
639  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_USER_NAME,
640  RecentActivityExtracterModuleFactory.getModuleName(), userName));
641  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_PROG_NAME,
642  RecentActivityExtracterModuleFactory.getModuleName(), browserName));
643 
644  try {
645  art = createArtifactWithAttributes(localStateArtifactType, extensionFile, bbattributes);
646  bbartifacts.add(art);
647  } catch (TskCoreException ex) {
648  logger.log(Level.SEVERE, String.format("Failed to create Extension artifact for file (%d)", extensionFile.getId()), ex);
649  }
650  }
651 
652  if (!context.dataSourceIngestIsCancelled()) {
653  postArtifacts(bbartifacts);
654  }
655  bbartifacts.clear();
656 
657  }
658  }
659 
667  private void getHistory(String browser, String browserLocation, String userName, long ingestJobId) {
668  FileManager fileManager = currentCase.getServices().getFileManager();
669  String browserName = browser;
670  List<AbstractFile> historyFiles;
671  String historyFileName = HISTORY_FILE_NAME;
672  if (browserName.equals(UC_BROWSER_NAME)) {
673  historyFileName = HISTORY_FILE_NAME + "%";
674  }
675  try {
676  historyFiles = fileManager.findFiles(dataSource, historyFileName, browserLocation); //NON-NLS
677  } catch (TskCoreException ex) {
678  String msg = NbBundle.getMessage(this.getClass(), "Chrome.getHistory.errMsg.errGettingFiles");
679  logger.log(Level.SEVERE, msg, ex);
680  this.addErrorMessage(this.getDisplayName() + ": " + msg);
681  return;
682  }
683 
684  // get only the allocated ones, for now
685  List<AbstractFile> allocatedHistoryFiles = new ArrayList<>();
686  for (AbstractFile historyFile : historyFiles) {
687  if (historyFile.isMetaFlagSet(TskData.TSK_FS_META_FLAG_ENUM.ALLOC)) {
688  allocatedHistoryFiles.add(historyFile);
689  }
690  }
691 
692  // log a message if we don't have any allocated history files
693  if (allocatedHistoryFiles.isEmpty()) {
694  String msg = NbBundle.getMessage(this.getClass(), "Chrome.getHistory.errMsg.couldntFindAnyFiles");
695  logger.log(Level.INFO, msg);
696  return;
697  }
698 
699  dataFound = true;
700  Collection<BlackboardArtifact> bbartifacts = new ArrayList<>();
701  int j = 0;
702  while (j < allocatedHistoryFiles.size()) {
703  if (browser.contains(GOOGLE_PROFILE_NAME)) {
704  String parentPath = FilenameUtils.normalizeNoEndSeparator(allocatedHistoryFiles.get(j).getParentPath());
705  browserName = GOOGLE_PROFILE + " " + FilenameUtils.getBaseName(parentPath);
706  }
707  String temps = RAImageIngestModule.getRATempPath(currentCase, browserName, ingestJobId) + File.separator + allocatedHistoryFiles.get(j).getName() + j + ".db"; //NON-NLS
708  final AbstractFile historyFile = allocatedHistoryFiles.get(j++);
709  if ((historyFile.getSize() == 0) || (historyFile.getName().toLowerCase().contains("-slack"))
710  || (historyFile.getName().toLowerCase().contains("cache")) || (historyFile.getName().toLowerCase().contains("media"))
711  || (historyFile.getName().toLowerCase().contains("index"))) {
712  continue;
713  }
714  try {
715  ContentUtils.writeToFile(historyFile, new File(temps), context::dataSourceIngestIsCancelled);
716  } catch (ReadContentInputStreamException ex) {
717  logger.log(Level.WARNING, String.format("Error reading Chrome web history artifacts file '%s' (id=%d).",
718  historyFile.getName(), historyFile.getId()), ex); //NON-NLS
719  this.addErrorMessage(NbBundle.getMessage(this.getClass(), "Chrome.getHistory.errMsg.errAnalyzingFile",
720  this.getDisplayName(), historyFile.getName()));
721  continue;
722  } catch (IOException ex) {
723  logger.log(Level.SEVERE, String.format("Error writing temp sqlite db file '%s' for Chrome web history artifacts file '%s' (id=%d).",
724  temps, historyFile.getName(), historyFile.getId()), ex); //NON-NLS
725  this.addErrorMessage(NbBundle.getMessage(this.getClass(), "Chrome.getHistory.errMsg.errAnalyzingFile",
726  this.getDisplayName(), historyFile.getName()));
727  continue;
728  }
729  File dbFile = new File(temps);
730  if (context.dataSourceIngestIsCancelled()) {
731  dbFile.delete();
732  break;
733  }
734  List<HashMap<String, Object>> tempList;
735  tempList = this.querySQLiteDb(temps, HISTORY_QUERY);
736  logger.log(Level.INFO, "{0}- Now getting history from {1} with {2} artifacts identified.", new Object[]{getDisplayName(), temps, tempList.size()}); //NON-NLS
737  for (HashMap<String, Object> result : tempList) {
738  String url = result.get("url") == null ? "" : result.get("url").toString();
739  String extractedDomain = NetworkUtils.extractDomain(url);
740 
741  try {
742  Collection<BlackboardAttribute> bbattributes = createHistoryAttributes(
743  StringUtils.defaultString(url),
744  (Long.valueOf(result.get("last_visit_time").toString()) / 1000000) - Long.valueOf("11644473600"),
745  result.get("from_visit") == null ? "" : result.get("from_visit").toString(),
746  result.get("title") == null ? "" : result.get("title").toString(),
747  browserName,
748  extractedDomain,
749  userName);
750 
751  bbartifacts.add(createArtifactWithAttributes(BlackboardArtifact.Type.TSK_WEB_HISTORY, historyFile, bbattributes));
752  } catch (TskCoreException ex) {
753  logger.log(Level.SEVERE, String.format("Failed to create history artifact for file (%d)", historyFile.getId()), ex);
754  }
755  }
756  dbFile.delete();
757  }
758 
759  if (!bbartifacts.isEmpty() && !context.dataSourceIngestIsCancelled()) {
760  postArtifacts(bbartifacts);
761  }
762  }
763 
771  private void getBookmark(String browser, String browserLocation, String userName, long ingestJobId) {
772  FileManager fileManager = currentCase.getServices().getFileManager();
773  List<AbstractFile> bookmarkFiles;
774  String browserName = browser;
775  String bookmarkFileName = BOOKMARK_FILE_NAME;
776  if (browserName.equals(UC_BROWSER_NAME)) {
777  bookmarkFileName = BOOKMARK_FILE_NAME + "%";
778  }
779  try {
780  bookmarkFiles = fileManager.findFiles(dataSource, bookmarkFileName, browserLocation); //NON-NLS
781  } catch (TskCoreException ex) {
782  String msg = NbBundle.getMessage(this.getClass(), "Chrome.getBookmark.errMsg.errGettingFiles");
783  logger.log(Level.SEVERE, msg, ex);
784  this.addErrorMessage(this.getDisplayName() + ": " + msg);
785  return;
786  }
787 
788  if (bookmarkFiles.isEmpty()) {
789  logger.log(Level.INFO, "Didn't find any Chrome bookmark files."); //NON-NLS
790  return;
791  }
792 
793  dataFound = true;
794  Collection<BlackboardArtifact> bbartifacts = new ArrayList<>();
795  int j = 0;
796  while (j < bookmarkFiles.size()) {
797  if (browser.contains(GOOGLE_PROFILE_NAME)) {
798  String parentPath = FilenameUtils.normalizeNoEndSeparator(bookmarkFiles.get(j).getParentPath());
799  browserName = GOOGLE_PROFILE + " " + FilenameUtils.getBaseName(parentPath);
800  }
801 
802  AbstractFile bookmarkFile = bookmarkFiles.get(j++);
803  if ((bookmarkFile.getSize() == 0) || (bookmarkFile.getName().toLowerCase().contains("-slack"))
804  || (bookmarkFile.getName().toLowerCase().contains("extras")) || (bookmarkFile.getName().toLowerCase().contains("log"))
805  || (bookmarkFile.getName().toLowerCase().contains("backup")) || (bookmarkFile.getName().toLowerCase().contains("visualized"))
806  || (bookmarkFile.getName().toLowerCase().contains("bak")) || (bookmarkFile.getParentPath().toLowerCase().contains("backup"))) {
807  continue;
808  }
809  String temps = RAImageIngestModule.getRATempPath(currentCase, browserName, ingestJobId) + File.separator + bookmarkFile.getName() + j + ".db"; //NON-NLS
810  try {
811  ContentUtils.writeToFile(bookmarkFile, new File(temps), context::dataSourceIngestIsCancelled);
812  } catch (ReadContentInputStreamException ex) {
813  logger.log(Level.WARNING, String.format("Error reading Chrome bookmark artifacts file '%s' (id=%d).",
814  bookmarkFile.getName(), bookmarkFile.getId()), ex); //NON-NLS
815  this.addErrorMessage(NbBundle.getMessage(this.getClass(), "Chrome.getBookmark.errMsg.errAnalyzingFile",
816  this.getDisplayName(), bookmarkFile.getName()));
817  continue;
818  } catch (IOException ex) {
819  logger.log(Level.SEVERE, String.format("Error writing temp sqlite db file '%s' for Chrome bookmark artifacts file '%s' (id=%d).",
820  temps, bookmarkFile.getName(), bookmarkFile.getId()), ex); //NON-NLS
821  this.addErrorMessage(NbBundle.getMessage(this.getClass(), "Chrome.getBookmark.errMsg.errAnalyzingFile",
822  this.getDisplayName(), bookmarkFile.getName()));
823  continue;
824  }
825 
826  logger.log(Level.INFO, "{0}- Now getting Bookmarks from {1}", new Object[]{getDisplayName(), temps}); //NON-NLS
827  File dbFile = new File(temps);
828  if (context.dataSourceIngestIsCancelled()) {
829  dbFile.delete();
830  break;
831  }
832 
833  FileReader tempReader;
834  try {
835  tempReader = new FileReader(temps);
836  } catch (FileNotFoundException ex) {
837  logger.log(Level.WARNING, "Error while trying to read into the Bookmarks for Chrome.", ex); //NON-NLS
838  continue;
839  }
840 
841  JsonElement jsonElement;
842  JsonObject jElement, jRoot;
843 
844  try {
845  jsonElement = JsonParser.parseReader(tempReader);
846  jElement = jsonElement.getAsJsonObject();
847  jRoot = jElement.get("roots").getAsJsonObject(); //NON-NLS
848  Set<String> bookmarkKeys = jRoot.keySet();
849  } catch (JsonIOException | JsonSyntaxException | IllegalStateException ex) {
850  logger.log(Level.WARNING, "Error parsing Json from Chrome Bookmark.", ex); //NON-NLS
851  this.addErrorMessage(NbBundle.getMessage(this.getClass(), "Chrome.getBookmark.errMsg.errAnalyzingFile3",
852  this.getDisplayName(), bookmarkFile.getName()));
853  continue;
854  }
855 
856  Set<String> bookmarkKeys = jRoot.keySet();
857  for (String bookmarkKey : bookmarkKeys) {
858  JsonObject jBookmark = jRoot.get(bookmarkKey).getAsJsonObject(); //NON-NLS
859  if (jBookmark.has("children")) {
860  JsonArray jBookmarkArray = jBookmark.getAsJsonArray("children"); //NON-NLS
861  for (JsonElement result : jBookmarkArray) {
862  JsonObject address = result.getAsJsonObject();
863  if (address == null) {
864  continue;
865  }
866  JsonElement urlEl = address.get("url"); //NON-NLS
867  String url;
868  if (urlEl != null) {
869  url = urlEl.getAsString();
870  } else {
871  url = "";
872  }
873  String name;
874  JsonElement nameEl = address.get("name"); //NON-NLS
875  if (nameEl != null) {
876  name = nameEl.getAsString();
877  } else {
878  name = "";
879  }
880  Long date;
881  JsonElement dateEl = address.get("date_added"); //NON-NLS
882  if (dateEl != null) {
883  date = dateEl.getAsLong();
884  } else {
885  date = Long.valueOf(0);
886  }
887  String domain = NetworkUtils.extractDomain(url);
888  Collection<BlackboardAttribute> bbattributes = new ArrayList<>();
889  //TODO Revisit usage of deprecated constructor as per TSK-583
890  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_URL,
891  RecentActivityExtracterModuleFactory.getModuleName(), url));
892  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_TITLE,
893  RecentActivityExtracterModuleFactory.getModuleName(), name));
894  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DATETIME_CREATED,
895  RecentActivityExtracterModuleFactory.getModuleName(), (date / 1000000) - Long.valueOf("11644473600")));
896  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_PROG_NAME,
897  RecentActivityExtracterModuleFactory.getModuleName(), browserName));
898  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DOMAIN,
899  RecentActivityExtracterModuleFactory.getModuleName(), domain));
900  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_USER_NAME,
901  RecentActivityExtracterModuleFactory.getModuleName(), userName));
902  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_COMMENT,
903  RecentActivityExtracterModuleFactory.getModuleName(), bookmarkKey));
904 
905 
906  try {
907  bbartifacts.add(createArtifactWithAttributes(BlackboardArtifact.Type.TSK_WEB_BOOKMARK, bookmarkFile, bbattributes));
908  } catch (TskCoreException ex) {
909  logger.log(Level.SEVERE, String.format("Failed to create bookmark artifact for file (%d)", bookmarkFile.getId()), ex);
910  }
911 
912  }
913  }
914  }
915 
916  if (!context.dataSourceIngestIsCancelled()) {
917  postArtifacts(bbartifacts);
918  }
919  bbartifacts.clear();
920  dbFile.delete();
921  }
922  }
923 
931  private void getCookie(String browser, String browserLocation, String userName, long ingestJobId) {
932 
933  FileManager fileManager = currentCase.getServices().getFileManager();
934  List<AbstractFile> cookiesFiles;
935  String browserName = browser;
936  String cookieFileName = COOKIE_FILE_NAME;
937  if (browserName.equals(UC_BROWSER_NAME)) {
938  // Wildcard on front and back of Cookies are there for Cookie files that start with something else
939  // ie: UC browser has "Extension Cookies.9" as well as Cookies.9
940  cookieFileName = "%" + COOKIE_FILE_NAME + "%";
941  }
942  try {
943  cookiesFiles = fileManager.findFiles(dataSource, cookieFileName, browserLocation); //NON-NLS
944  } catch (TskCoreException ex) {
945  String msg = NbBundle.getMessage(this.getClass(), "Chrome.getCookie.errMsg.errGettingFiles");
946  logger.log(Level.SEVERE, msg, ex);
947  this.addErrorMessage(this.getDisplayName() + ": " + msg);
948  return;
949  }
950 
951  if (cookiesFiles.isEmpty()) {
952  logger.log(Level.INFO, "Didn't find any Chrome cookies files."); //NON-NLS
953  return;
954  }
955 
956  dataFound = true;
957  Collection<BlackboardArtifact> bbartifacts = new ArrayList<>();
958  int j = 0;
959  while (j < cookiesFiles.size()) {
960  if (browser.contains(GOOGLE_PROFILE_NAME)) {
961  String parentPath = FilenameUtils.normalizeNoEndSeparator(cookiesFiles.get(j).getParentPath());
962  browserName = GOOGLE_PROFILE + FilenameUtils.getBaseName(parentPath);
963  }
964 
965  AbstractFile cookiesFile = cookiesFiles.get(j++);
966  if ((cookiesFile.getSize() == 0) || (cookiesFile.getName().toLowerCase().contains("-slack"))) {
967  continue;
968  }
969  String temps = RAImageIngestModule.getRATempPath(currentCase, browserName, ingestJobId) + File.separator + cookiesFile.getName() + j + ".db"; //NON-NLS
970  try {
971  ContentUtils.writeToFile(cookiesFile, new File(temps), context::dataSourceIngestIsCancelled);
972  } catch (ReadContentInputStreamException ex) {
973  logger.log(Level.WARNING, String.format("Error reading Chrome cookie artifacts file '%s' (id=%d).",
974  cookiesFile.getName(), cookiesFile.getId()), ex); //NON-NLS
975  this.addErrorMessage(NbBundle.getMessage(this.getClass(), "Chrome.getCookie.errMsg.errAnalyzeFile",
976  this.getDisplayName(), cookiesFile.getName()));
977  continue;
978  } catch (IOException ex) {
979  logger.log(Level.SEVERE, String.format("Error writing temp sqlite db file '%s' for Chrome cookie artifacts file '%s' (id=%d).",
980  temps, cookiesFile.getName(), cookiesFile.getId()), ex); //NON-NLS
981  this.addErrorMessage(NbBundle.getMessage(this.getClass(), "Chrome.getCookie.errMsg.errAnalyzeFile",
982  this.getDisplayName(), cookiesFile.getName()));
983  continue;
984  }
985  File dbFile = new File(temps);
986  if (context.dataSourceIngestIsCancelled()) {
987  dbFile.delete();
988  break;
989  }
990 
991  List<HashMap<String, Object>> tempList = this.querySQLiteDb(temps, COOKIE_QUERY);
992  logger.log(Level.INFO, "{0}- Now getting cookies from {1} with {2} artifacts identified.", new Object[]{getDisplayName(), temps, tempList.size()}); //NON-NLS
993  for (HashMap<String, Object> result : tempList) {
994  Collection<BlackboardAttribute> bbattributes = new ArrayList<>();
995  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_URL,
996  RecentActivityExtracterModuleFactory.getModuleName(),
997  ((result.get("host_key").toString() != null) ? result.get("host_key").toString() : ""))); //NON-NLS
998  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DATETIME_ACCESSED,
999  RecentActivityExtracterModuleFactory.getModuleName(),
1000  (Long.valueOf(result.get("last_access_utc").toString()) / 1000000) - Long.valueOf("11644473600"))); //NON-NLS
1001 
1002  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_NAME,
1003  RecentActivityExtracterModuleFactory.getModuleName(),
1004  ((result.get("name").toString() != null) ? result.get("name").toString() : ""))); //NON-NLS
1005  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_VALUE,
1006  RecentActivityExtracterModuleFactory.getModuleName(),
1007  ((result.get("value").toString() != null) ? result.get("value").toString() : ""))); //NON-NLS
1008  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_PROG_NAME,
1009  RecentActivityExtracterModuleFactory.getModuleName(), browserName));
1010  String domain = result.get("host_key").toString(); //NON-NLS
1011  domain = domain.replaceFirst("^\\.+(?!$)", "");
1012  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DOMAIN,
1013  RecentActivityExtracterModuleFactory.getModuleName(), domain));
1014  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_USER_NAME,
1015  RecentActivityExtracterModuleFactory.getModuleName(), userName));
1016 
1017  try {
1018  bbartifacts.add(createArtifactWithAttributes(BlackboardArtifact.Type.TSK_WEB_COOKIE, cookiesFile, bbattributes));
1019  } catch (TskCoreException ex) {
1020  logger.log(Level.SEVERE, String.format("Failed to create cookie artifact for file (%d)", cookiesFile.getId()), ex);
1021  }
1022  }
1023 
1024  dbFile.delete();
1025  }
1026 
1027  if (!bbartifacts.isEmpty() && !context.dataSourceIngestIsCancelled()) {
1028  postArtifacts(bbartifacts);
1029  }
1030  }
1031 
1039  private void getDownload(String browser, String browserLocation, String userName, long ingestJobId) {
1040  FileManager fileManager = currentCase.getServices().getFileManager();
1041  List<AbstractFile> downloadFiles;
1042  String browserName = browser;
1043  String historyFileName = HISTORY_FILE_NAME;
1044  if (browserName.equals(UC_BROWSER_NAME)) {
1045  historyFileName = HISTORY_FILE_NAME + "%";
1046  }
1047  try {
1048  downloadFiles = fileManager.findFiles(dataSource, historyFileName, browserLocation); //NON-NLS
1049  } catch (TskCoreException ex) {
1050  String msg = NbBundle.getMessage(this.getClass(), "Chrome.getDownload.errMsg.errGettingFiles");
1051  logger.log(Level.SEVERE, msg, ex);
1052  this.addErrorMessage(this.getDisplayName() + ": " + msg);
1053  return;
1054  }
1055 
1056  if (downloadFiles.isEmpty()) {
1057  logger.log(Level.INFO, "Didn't find any Chrome download files."); //NON-NLS
1058  return;
1059  }
1060 
1061  dataFound = true;
1062  Collection<BlackboardArtifact> bbartifacts = new ArrayList<>();
1063  int j = 0;
1064  while (j < downloadFiles.size()) {
1065  if (browser.contains(GOOGLE_PROFILE_NAME)) {
1066  String parentPath = FilenameUtils.normalizeNoEndSeparator(downloadFiles.get(j).getParentPath());
1067  browserName = GOOGLE_PROFILE + FilenameUtils.getBaseName(parentPath);
1068  }
1069 
1070  AbstractFile downloadFile = downloadFiles.get(j++);
1071  if ((downloadFile.getSize() == 0) || (downloadFile.getName().toLowerCase().contains("-slack"))
1072  || (downloadFile.getName().toLowerCase().contains("cache")) || (downloadFile.getName().toLowerCase().contains("index"))) {
1073  continue;
1074  }
1075 
1076  String temps = RAImageIngestModule.getRATempPath(currentCase, browserName, ingestJobId) + File.separator + downloadFile.getName() + j + ".db"; //NON-NLS
1077  try {
1078  ContentUtils.writeToFile(downloadFile, new File(temps), context::dataSourceIngestIsCancelled);
1079  } catch (ReadContentInputStreamException ex) {
1080  logger.log(Level.WARNING, String.format("Error reading Chrome download artifacts file '%s' (id=%d).",
1081  downloadFile.getName(), downloadFile.getId()), ex); //NON-NLS
1082  this.addErrorMessage(NbBundle.getMessage(this.getClass(), "Chrome.getDownload.errMsg.errAnalyzeFiles1",
1083  this.getDisplayName(), downloadFile.getName()));
1084  continue;
1085  } catch (IOException ex) {
1086  logger.log(Level.SEVERE, String.format("Error writing temp sqlite db file '%s' for Chrome download artifacts file '%s' (id=%d).",
1087  temps, downloadFile.getName(), downloadFile.getId()), ex); //NON-NLS
1088  this.addErrorMessage(NbBundle.getMessage(this.getClass(), "Chrome.getDownload.errMsg.errAnalyzeFiles1",
1089  this.getDisplayName(), downloadFile.getName()));
1090  continue;
1091  }
1092  File dbFile = new File(temps);
1093  if (context.dataSourceIngestIsCancelled()) {
1094  dbFile.delete();
1095  break;
1096  }
1097 
1098  List<HashMap<String, Object>> tempList;
1099 
1100  if (isChromePreVersion30(temps)) {
1101  tempList = this.querySQLiteDb(temps, DOWNLOAD_QUERY);
1102  } else {
1103  tempList = this.querySQLiteDb(temps, DOWNLOAD_QUERY_V30);
1104  }
1105 
1106  logger.log(Level.INFO, "{0}- Now getting downloads from {1} with {2} artifacts identified.", new Object[]{getDisplayName(), temps, tempList.size()}); //NON-NLS
1107  for (HashMap<String, Object> result : tempList) {
1108  Collection<BlackboardAttribute> bbattributes = new ArrayList<>();
1109  String fullPath = result.get("full_path").toString(); //NON-NLS
1110  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_PATH,
1111  RecentActivityExtracterModuleFactory.getModuleName(), fullPath));
1112  long pathID = Util.findID(dataSource, fullPath);
1113  if (pathID != -1) {
1114  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_PATH_ID,
1115  NbBundle.getMessage(this.getClass(),
1116  "Chrome.parentModuleName"), pathID));
1117  }
1118  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_URL,
1119  RecentActivityExtracterModuleFactory.getModuleName(),
1120  ((result.get("url").toString() != null) ? result.get("url").toString() : ""))); //NON-NLS
1121  //bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_URL_DECODED.getTypeID(), "Recent Activity", ((result.get("url").toString() != null) ? EscapeUtil.decodeURL(result.get("url").toString()) : "")));
1122  Long time = (Long.valueOf(result.get("start_time").toString()) / 1000000) - Long.valueOf("11644473600"); //NON-NLS
1123 
1124  //TODO Revisit usage of deprecated constructor as per TSK-583
1125  //bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_LAST_ACCESSED.getTypeID(), "Recent Activity", "Last Visited", time));
1126  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DATETIME_ACCESSED,
1127  RecentActivityExtracterModuleFactory.getModuleName(), time));
1128  String domain = NetworkUtils.extractDomain((result.get("url").toString() != null) ? result.get("url").toString() : ""); //NON-NLS
1129  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DOMAIN,
1130  RecentActivityExtracterModuleFactory.getModuleName(), domain));
1131  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_USER_NAME,
1132  RecentActivityExtracterModuleFactory.getModuleName(), userName));
1133  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_PROG_NAME,
1134  RecentActivityExtracterModuleFactory.getModuleName(), browserName));
1135 
1136  // find the downloaded file and create a TSK_ASSOCIATED_OBJECT for it, associating it with the TSK_WEB_DOWNLOAD artifact.
1137  try {
1138  BlackboardArtifact webDownloadArtifact = createArtifactWithAttributes(BlackboardArtifact.Type.TSK_WEB_DOWNLOAD, downloadFile, bbattributes);
1139  bbartifacts.add(webDownloadArtifact);
1140  String normalizedFullPath = FilenameUtils.normalize(fullPath, true);
1141  for (AbstractFile downloadedFile : currentCase.getSleuthkitCase().getFileManager().findFilesExactNameExactPath(dataSource, FilenameUtils.getName(normalizedFullPath), FilenameUtils.getPath(normalizedFullPath))) {
1142  bbartifacts.add(createAssociatedArtifact(downloadedFile, webDownloadArtifact));
1143  break;
1144  }
1145  } catch (TskCoreException ex) {
1146  logger.log(Level.SEVERE, String.format("Error creating associated object artifact for file '%s'", fullPath), ex); //NON-NLS
1147  }
1148  }
1149 
1150  dbFile.delete();
1151  }
1152 
1153  if (!bbartifacts.isEmpty() && !context.dataSourceIngestIsCancelled()) {
1154  postArtifacts(bbartifacts);
1155  }
1156  }
1157 
1165  private void getFavicons(String browser, String browserLocation, String userName, long ingestJobId) {
1166  FileManager fileManager = currentCase.getServices().getFileManager();
1167  List<AbstractFile> faviconFiles;
1168  String browserName = browser;
1169  try {
1170  faviconFiles = fileManager.findFiles(dataSource, FAVICON_DATA_FILE_NAME, browserLocation); //NON-NLS
1171  } catch (TskCoreException ex) {
1172  String msg = NbBundle.getMessage(this.getClass(), "Chrome.getFavicon.errMsg.errGettingFiles");
1173  logger.log(Level.SEVERE, msg, ex);
1174  this.addErrorMessage(this.getDisplayName() + ": " + msg);
1175  return;
1176  }
1177 
1178  if (faviconFiles.isEmpty()) {
1179  logger.log(Level.INFO, "Didn't find any Chrome favicon files."); //NON-NLS
1180  return;
1181  }
1182 
1183  dataFound = true;
1184  Collection<BlackboardArtifact> bbartifacts = new ArrayList<>();
1185  int j = 0;
1186  while (j < faviconFiles.size()) {
1187  if (browser.contains(GOOGLE_PROFILE_NAME)) {
1188  String parentPath = FilenameUtils.normalizeNoEndSeparator(faviconFiles.get(j).getParentPath());
1189  browserName = GOOGLE_PROFILE + FilenameUtils.getBaseName(parentPath);
1190  }
1191  AbstractFile faviconFile = faviconFiles.get(j++);
1192  if ((faviconFile.getSize() == 0) || (faviconFile.getName().toLowerCase().contains("-slack"))
1193  || (faviconFile.getName().toLowerCase().contains("cache")) || (faviconFile.getName().toLowerCase().contains("index"))) {
1194  continue;
1195  }
1196 
1197  String temps = RAImageIngestModule.getRATempPath(currentCase, browserName, ingestJobId) + File.separator + faviconFile.getName() + j + ".db"; //NON-NLS
1198  try {
1199  ContentUtils.writeToFile(faviconFile, new File(temps), context::dataSourceIngestIsCancelled);
1200  } catch (ReadContentInputStreamException ex) {
1201  logger.log(Level.WARNING, String.format("Error reading Chrome favicons artifacts file '%s' (id=%d).",
1202  faviconFile.getName(), faviconFile.getId()), ex); //NON-NLS
1203  this.addErrorMessage(NbBundle.getMessage(this.getClass(), "Chrome.getFavicon.errMsg.errAnalyzeFiles1",
1204  this.getDisplayName(), faviconFile.getName()));
1205  continue;
1206  } catch (IOException ex) {
1207  logger.log(Level.SEVERE, String.format("Error writing temp sqlite db file '%s' for Chrome favicon artifacts file '%s' (id=%d).",
1208  temps, faviconFile.getName(), faviconFile.getId()), ex); //NON-NLS
1209  this.addErrorMessage(NbBundle.getMessage(this.getClass(), "Chrome.getfavicon.errMsg.errAnalyzeFiles1",
1210  this.getDisplayName(), faviconFile.getName()));
1211  continue;
1212  }
1213  File dbFile = new File(temps);
1214  if (context.dataSourceIngestIsCancelled()) {
1215  dbFile.delete();
1216  break;
1217  }
1218 
1219  BlackboardArtifact.Type faviconArtifactType;
1220 
1221  try {
1222  faviconArtifactType = createArtifactType(FAVICON_ARTIFACT_NAME, NbBundle.getMessage(this.getClass(), "Chrome.getFavicon.displayName"));
1223  } catch (TskCoreException ex) {
1224  logger.log(Level.SEVERE, String.format("Error creating artifact type for Chrome favicon."), ex); //NON-NLS
1225  this.addErrorMessage(NbBundle.getMessage(this.getClass(), "Chrome.getfavicon.errMsg.errCreateArtifact"));
1226  continue;
1227 
1228  }
1229 
1230  List<HashMap<String, Object>> tempList;
1231 
1232  tempList = this.querySQLiteDb(temps, FAVICON_QUERY);
1233 
1234  logger.log(Level.INFO, "{0}- Now getting favicons from {1} with {2} artifacts identified.", new Object[]{getDisplayName(), temps, tempList.size()}); //NON-NLS
1235  for (HashMap<String, Object> result : tempList) {
1236  Collection<BlackboardAttribute> bbattributes = new ArrayList<>();
1237  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_URL,
1238  RecentActivityExtracterModuleFactory.getModuleName(),
1239  ((result.get("page_url").toString() != null) ? result.get("page_url").toString() : ""))); //NON-NLS
1240  Long updatedTime = (Long.valueOf(result.get("last_updated").toString()) / 1000000) - Long.valueOf("11644473600"); //NON-NLS
1241  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DATETIME_MODIFIED,
1242  RecentActivityExtracterModuleFactory.getModuleName(), updatedTime));
1243  Long requestedTime = (Long.valueOf(result.get("last_requested").toString()) / 1000000) - Long.valueOf("11644473600"); //NON-NLS
1244  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DATETIME_ACCESSED,
1245  RecentActivityExtracterModuleFactory.getModuleName(), requestedTime));
1246  String domain = NetworkUtils.extractDomain((result.get("page_url").toString() != null) ? result.get("page_url").toString() : ""); //NON-NLS
1247  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DOMAIN,
1248  RecentActivityExtracterModuleFactory.getModuleName(), domain));
1249  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_USER_NAME,
1250  RecentActivityExtracterModuleFactory.getModuleName(), userName));
1251  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_PROG_NAME,
1252  RecentActivityExtracterModuleFactory.getModuleName(), browserName));
1253 
1254  try {
1255  bbartifacts.add(createArtifactWithAttributes(faviconArtifactType, faviconFile, bbattributes));
1256  } catch (TskCoreException ex) {
1257  logger.log(Level.SEVERE, String.format("Failed to create cookie artifact for file (%d)", faviconFile.getId()), ex);
1258  }
1259 
1260  }
1261 
1262  dbFile.delete();
1263  }
1264 
1265  if (!bbartifacts.isEmpty() && !context.dataSourceIngestIsCancelled()) {
1266  postArtifacts(bbartifacts);
1267  }
1268  }
1269 
1277  private void getLogins(String browser, String browserLocation, String userName, long ingestJobId) {
1278 
1279  FileManager fileManager = currentCase.getServices().getFileManager();
1280  List<AbstractFile> loginDataFiles;
1281  String browserName = browser;
1282  String loginDataFileName = LOGIN_DATA_FILE_NAME;
1283  if (browserName.equals(UC_BROWSER_NAME)) {
1284  loginDataFileName = LOGIN_DATA_FILE_NAME + "%";
1285  }
1286 
1287  try {
1288  loginDataFiles = fileManager.findFiles(dataSource, loginDataFileName, browserLocation); //NON-NLS
1289  } catch (TskCoreException ex) {
1290  String msg = NbBundle.getMessage(this.getClass(), "Chrome.getLogin.errMsg.errGettingFiles");
1291  logger.log(Level.SEVERE, msg, ex);
1292  this.addErrorMessage(this.getDisplayName() + ": " + msg);
1293  return;
1294  }
1295 
1296  if (loginDataFiles.isEmpty()) {
1297  logger.log(Level.INFO, "Didn't find any Chrome Login Data files."); //NON-NLS
1298  return;
1299  }
1300 
1301  dataFound = true;
1302  Collection<BlackboardArtifact> bbartifacts = new ArrayList<>();
1303  int j = 0;
1304  while (j < loginDataFiles.size()) {
1305  if (browser.contains(GOOGLE_PROFILE_NAME)) {
1306  String parentPath = FilenameUtils.normalizeNoEndSeparator(loginDataFiles.get(j).getParentPath());
1307  browserName = GOOGLE_PROFILE + FilenameUtils.getBaseName(parentPath);
1308  }
1309  AbstractFile loginDataFile = loginDataFiles.get(j++);
1310  if ((loginDataFile.getSize() == 0) || (loginDataFile.getName().toLowerCase().contains("-slack"))) {
1311  continue;
1312  }
1313  String temps = RAImageIngestModule.getRATempPath(currentCase, browserName, ingestJobId) + File.separator + loginDataFile.getName() + j + ".db"; //NON-NLS
1314  try {
1315  ContentUtils.writeToFile(loginDataFile, new File(temps), context::dataSourceIngestIsCancelled);
1316  } catch (ReadContentInputStreamException ex) {
1317  logger.log(Level.WARNING, String.format("Error reading Chrome login artifacts file '%s' (id=%d).",
1318  loginDataFile.getName(), loginDataFile.getId()), ex); //NON-NLS
1319  this.addErrorMessage(NbBundle.getMessage(this.getClass(), "Chrome.getLogin.errMsg.errAnalyzingFiles",
1320  this.getDisplayName(), loginDataFile.getName()));
1321  continue;
1322  } catch (IOException ex) {
1323  logger.log(Level.SEVERE, String.format("Error writing temp sqlite db file '%s' for Chrome login artifacts file '%s' (id=%d).",
1324  temps, loginDataFile.getName(), loginDataFile.getId()), ex); //NON-NLS
1325  this.addErrorMessage(NbBundle.getMessage(this.getClass(), "Chrome.getLogin.errMsg.errAnalyzingFiles",
1326  this.getDisplayName(), loginDataFile.getName()));
1327  continue;
1328  }
1329  File dbFile = new File(temps);
1330  if (context.dataSourceIngestIsCancelled()) {
1331  dbFile.delete();
1332  break;
1333  }
1334  List<HashMap<String, Object>> tempList = this.querySQLiteDb(temps, LOGIN_QUERY);
1335  logger.log(Level.INFO, "{0}- Now getting login information from {1} with {2} artifacts identified.", new Object[]{getDisplayName(), temps, tempList.size()}); //NON-NLS
1336  for (HashMap<String, Object> result : tempList) {
1337  Collection<BlackboardAttribute> bbattributes = new ArrayList<>();
1338 
1339  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_URL,
1340  RecentActivityExtracterModuleFactory.getModuleName(),
1341  ((result.get("origin_url").toString() != null) ? result.get("origin_url").toString() : ""))); //NON-NLS
1342 
1343  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DATETIME_CREATED,
1344  RecentActivityExtracterModuleFactory.getModuleName(),
1345  (Long.valueOf(result.get("date_created").toString()) / 1000000) - Long.valueOf("11644473600"))); //NON-NLS
1346 
1347  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_URL_DECODED,
1348  RecentActivityExtracterModuleFactory.getModuleName(),
1349  (NetworkUtils.extractDomain((result.get("origin_url").toString() != null) ? result.get("origin_url").toString() : "")))); //NON-NLS
1350 
1351  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_USER_NAME,
1352  RecentActivityExtracterModuleFactory.getModuleName(),
1353  ((result.get("username_value").toString() != null) ? result.get("username_value").toString().replaceAll("'", "''") : ""))); //NON-NLS
1354 
1355  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_REALM,
1356  RecentActivityExtracterModuleFactory.getModuleName(),
1357  ((result.get("signon_realm") != null && result.get("signon_realm").toString() != null) ? result.get("signon_realm").toString() : ""))); //NON-NLS
1358 
1359  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DOMAIN,
1360  RecentActivityExtracterModuleFactory.getModuleName(),
1361  result.containsKey("signon_realm") ? NetworkUtils.extractDomain(result.get("signon_realm").toString()) : "")); //NON-NLS
1362 
1363  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_PROG_NAME,
1364  RecentActivityExtracterModuleFactory.getModuleName(), browserName));
1365 
1366  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_USER_NAME,
1367  RecentActivityExtracterModuleFactory.getModuleName(), userName));
1368 
1369  try {
1370  bbartifacts.add(createArtifactWithAttributes(BlackboardArtifact.Type.TSK_SERVICE_ACCOUNT, loginDataFile, bbattributes));
1371  } catch (TskCoreException ex) {
1372  logger.log(Level.SEVERE, String.format("Failed to create service account artifact for file (%d)", loginDataFile.getId()), ex);
1373  }
1374  }
1375 
1376  dbFile.delete();
1377  }
1378 
1379  if (!bbartifacts.isEmpty() && !context.dataSourceIngestIsCancelled()) {
1380  postArtifacts(bbartifacts);
1381  }
1382  }
1383 
1392  private void getAutofill(String browser, String browserLocation, String userName, long ingestJobId) {
1393 
1394  FileManager fileManager = currentCase.getServices().getFileManager();
1395  List<AbstractFile> webDataFiles;
1396  String browserName = browser;
1397  String webDataFileName = WEB_DATA_FILE_NAME;
1398  if (browserName.equals(UC_BROWSER_NAME)) {
1399  webDataFileName = WEB_DATA_FILE_NAME + "%";
1400  }
1401 
1402  try {
1403  webDataFiles = fileManager.findFiles(dataSource, webDataFileName, browserLocation); //NON-NLS
1404  } catch (TskCoreException ex) {
1405  String msg = NbBundle.getMessage(this.getClass(), "Chrome.getAutofills.errMsg.errGettingFiles");
1406  logger.log(Level.SEVERE, msg, ex);
1407  this.addErrorMessage(this.getDisplayName() + ": " + msg);
1408  return;
1409  }
1410 
1411  if (webDataFiles.isEmpty()) {
1412  logger.log(Level.INFO, "Didn't find any Chrome Web Data files."); //NON-NLS
1413  return;
1414  }
1415 
1416  dataFound = true;
1417  Collection<BlackboardArtifact> bbartifacts = new ArrayList<>();
1418  int j = 0;
1419  while (j < webDataFiles.size()) {
1420  if (browser.contains(GOOGLE_PROFILE_NAME)) {
1421  String parentPath = FilenameUtils.normalizeNoEndSeparator(webDataFiles.get(j).getParentPath());
1422  browserName = GOOGLE_PROFILE + FilenameUtils.getBaseName(parentPath);
1423  }
1424  databaseEncrypted = false;
1425  AbstractFile webDataFile = webDataFiles.get(j++);
1426  if ((webDataFile.getSize() == 0) || (webDataFile.getName().toLowerCase().contains("-slack"))) {
1427  continue;
1428  }
1429  String tempFilePath = RAImageIngestModule.getRATempPath(currentCase, browserName, ingestJobId) + File.separator + webDataFile.getName() + j + ".db"; //NON-NLS
1430  try {
1431  ContentUtils.writeToFile(webDataFile, new File(tempFilePath), context::dataSourceIngestIsCancelled);
1432  } catch (ReadContentInputStreamException ex) {
1433  logger.log(Level.WARNING, String.format("Error reading Chrome Autofill artifacts file '%s' (id=%d).",
1434  webDataFile.getName(), webDataFile.getId()), ex); //NON-NLS
1435  this.addErrorMessage(NbBundle.getMessage(this.getClass(), "Chrome.getAutofill.errMsg.errAnalyzingFiles",
1436  this.getDisplayName(), webDataFile.getName()));
1437  continue;
1438  } catch (IOException ex) {
1439  logger.log(Level.SEVERE, String.format("Error writing temp sqlite db file '%s' for Chrome Web data file '%s' (id=%d).",
1440  tempFilePath, webDataFile.getName(), webDataFile.getId()), ex); //NON-NLS
1441  this.addErrorMessage(NbBundle.getMessage(this.getClass(), "Chrome.getLogin.errMsg.errAnalyzingFiles",
1442  this.getDisplayName(), webDataFile.getName()));
1443  continue;
1444  }
1445  File dbFile = new File(tempFilePath);
1446  if (context.dataSourceIngestIsCancelled()) {
1447  dbFile.delete();
1448  break;
1449  }
1450 
1451  // The DB schema is little different in schema version 8x vs older versions
1452  boolean isSchemaV8X = Util.checkColumn("date_created", "autofill", tempFilePath);
1453 
1454  // get form autofill artifacts
1455  bbartifacts.addAll(getFormAutofillArtifacts(webDataFile, tempFilePath, isSchemaV8X, userName, browserName));
1456  try {
1457  // get form address atifacts
1458  getFormAddressArtifacts(webDataFile, tempFilePath, isSchemaV8X);
1459  if (databaseEncrypted) {
1460  String comment = String.format("%s Autofill Database Encryption Detected", browserName);
1461  Collection<BlackboardAttribute> bbattributes = Arrays.asList(
1462  new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_COMMENT,
1463  RecentActivityExtracterModuleFactory.getModuleName(), comment));
1464 
1465  bbartifacts.add(
1466  webDataFile.newAnalysisResult(
1467  BlackboardArtifact.Type.TSK_ENCRYPTION_DETECTED, Score.SCORE_NOTABLE,
1468  null, null, comment, bbattributes).getAnalysisResult());
1469  }
1470  } catch (NoCurrentCaseException | TskCoreException | Blackboard.BlackboardException ex) {
1471  logger.log(Level.SEVERE, String.format("Error adding artifacts to the case database "
1472  + "for chrome file %s [objId=%d]", webDataFile.getName(), webDataFile.getId()), ex);
1473  }
1474 
1475  dbFile.delete();
1476  }
1477 
1478  if (!bbartifacts.isEmpty() && !context.dataSourceIngestIsCancelled()) {
1479  postArtifacts(bbartifacts);
1480  }
1481  }
1482 
1493  private Collection<BlackboardArtifact> getFormAutofillArtifacts(AbstractFile webDataFile, String dbFilePath, boolean isSchemaV8X, String userName, String browser) {
1494 
1495  Collection<BlackboardArtifact> bbartifacts = new ArrayList<>();
1496 
1497  // The DB Schema is little different in version 8x vs older versions
1498  String autoFillquery = (isSchemaV8X) ? AUTOFILL_QUERY_V8X
1499  : AUTOFILL_QUERY;
1500 
1501  List<HashMap<String, Object>> autofills = this.querySQLiteDb(dbFilePath, autoFillquery);
1502  logger.log(Level.INFO, "{0}- Now getting Autofill information from {1} with {2} artifacts identified.", new Object[]{getDisplayName(), dbFilePath, autofills.size()}); //NON-NLS
1503  for (HashMap<String, Object> result : autofills) {
1504  Collection<BlackboardAttribute> bbattributes = new ArrayList<>();
1505 
1506  // extract all common attributes
1507  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_NAME,
1508  NbBundle.getMessage(this.getClass(), "Chrome.parentModuleName"),
1509  ((result.get("name").toString() != null) ? result.get("name").toString() : ""))); //NON-NLS
1510 
1511  fieldEncrypted = false;
1512  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_VALUE,
1513  RecentActivityExtracterModuleFactory.getModuleName(),
1514  processFields(result.get("value")))); //NON-NLS
1515 
1516  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_COUNT,
1517  RecentActivityExtracterModuleFactory.getModuleName(),
1518  (Integer.valueOf(result.get("count").toString())))); //NON-NLS
1519 
1520  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DATETIME_CREATED,
1521  RecentActivityExtracterModuleFactory.getModuleName(),
1522  Long.valueOf(result.get("date_created").toString()))); //NON-NLS
1523 
1524  // get schema version specific attributes
1525  if (isSchemaV8X) {
1526  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DATETIME_ACCESSED,
1527  RecentActivityExtracterModuleFactory.getModuleName(),
1528  Long.valueOf(result.get("date_last_used").toString()))); //NON-NLS
1529  }
1530 
1531  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_USER_NAME,
1532  RecentActivityExtracterModuleFactory.getModuleName(), userName));
1533  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_PROG_NAME,
1534  RecentActivityExtracterModuleFactory.getModuleName(), browser));
1535  if (fieldEncrypted) {
1536  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_COMMENT,
1537  RecentActivityExtracterModuleFactory.getModuleName(), ENCRYPTED_FIELD_MESSAGE));
1538  }
1539 
1540  // Add an artifact
1541  try {
1542  bbartifacts.add(createArtifactWithAttributes(BlackboardArtifact.Type.TSK_WEB_FORM_AUTOFILL, webDataFile, bbattributes));
1543  } catch (TskCoreException ex) {
1544  logger.log(Level.SEVERE, String.format("Failed to create web form autopfill artifact for file (%d)", webDataFile.getId()), ex);
1545  }
1546  }
1547 
1548  // return all extracted artifacts
1549  return bbartifacts;
1550  }
1551 
1563  private void getFormAddressArtifacts(AbstractFile webDataFile, String dbFilePath, boolean isSchemaV8X) throws NoCurrentCaseException,
1564  TskCoreException, Blackboard.BlackboardException {
1565 
1566  String webformAddressQuery = (isSchemaV8X) ? WEBFORM_ADDRESS_QUERY_V8X
1567  : WEBFORM_ADDRESS_QUERY;
1568 
1569  // Helper to create web form address artifacts.
1570  WebBrowserArtifactsHelper helper = new WebBrowserArtifactsHelper(
1571  Case.getCurrentCaseThrows().getSleuthkitCase(),
1572  NbBundle.getMessage(this.getClass(), "Chrome.parentModuleName"),
1573  webDataFile, context.getJobId()
1574  );
1575 
1576  // Get Web form addresses
1577  List<HashMap<String, Object>> addresses = this.querySQLiteDb(dbFilePath, webformAddressQuery);
1578  logger.log(Level.INFO, "{0}- Now getting Web form addresses from {1} with {2} artifacts identified.", new Object[]{getDisplayName(), dbFilePath, addresses.size()}); //NON-NLS
1579  for (HashMap<String, Object> result : addresses) {
1580 
1581  fieldEncrypted = false;
1582 
1583  String first_name = processFields(result.get("first_name"));
1584  String middle_name = processFields(result.get("middle_name"));
1585  String last_name = processFields(result.get("last_name"));
1586 
1587  // get email and phone
1588  String email_Addr = processFields(result.get("email"));
1589  String phone_number = processFields(result.get("number"));
1590 
1591  // Get the address fields
1592  String city = processFields(result.get("city"));
1593  String state = processFields(result.get("state"));
1594  String zipcode = processFields(result.get("zipcode"));
1595  String country_code = processFields(result.get("country_code"));
1596 
1597  // schema version specific fields
1598  String full_name = "";
1599  String street_address = "";
1600  long date_modified = 0;
1601  int use_count = 0;
1602  long use_date = 0;
1603 
1604  if (isSchemaV8X) {
1605 
1606  full_name = processFields(result.get("full_name"));
1607  street_address = processFields(result.get("street_address"));
1608  date_modified = result.get("date_modified").toString() != null ? Long.valueOf(result.get("date_modified").toString()) : 0;
1609  use_count = result.get("use_count").toString() != null ? Integer.valueOf(result.get("use_count").toString()) : 0;
1610  use_date = result.get("use_date").toString() != null ? Long.valueOf(result.get("use_date").toString()) : 0;
1611  } else {
1612  String address_line_1 = processFields(result.get("address_line_1"));
1613  String address_line_2 = processFields(result.get("address_line_2"));
1614  street_address = String.join(" ", address_line_1, address_line_2);
1615  }
1616 
1617  // Create atrributes from extracted fields
1618  if (full_name == null || full_name.isEmpty()) {
1619  full_name = String.join(" ", first_name, middle_name, last_name);
1620  }
1621 
1622  String locationAddress = String.join(", ", street_address, city, state, zipcode, country_code);
1623 
1624  List<BlackboardAttribute> otherAttributes = new ArrayList<>();
1625  if (date_modified > 0) {
1626  otherAttributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DATETIME_MODIFIED,
1627  RecentActivityExtracterModuleFactory.getModuleName(),
1628  date_modified)); //NON-NLS
1629  if (fieldEncrypted) {
1630  otherAttributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_COMMENT,
1631  RecentActivityExtracterModuleFactory.getModuleName(), ENCRYPTED_FIELD_MESSAGE)); //NON-NLS
1632 
1633  }
1634  }
1635 
1636  helper.addWebFormAddress(
1637  full_name, email_Addr, phone_number,
1638  locationAddress, 0, use_date,
1639  use_count, otherAttributes);
1640  }
1641  }
1642 
1652  private String processFields(Object dataValue) {
1653 
1654  if (dataValue instanceof byte[]) {
1655  fieldEncrypted = true;
1656  databaseEncrypted = true;
1657  }
1658 
1659  return dataValue.toString() != null ? dataValue.toString() : "";
1660 
1661  }
1662 
1663  private boolean isChromePreVersion30(String temps) {
1664  String query = "PRAGMA table_info(downloads)"; //NON-NLS
1665  List<HashMap<String, Object>> columns = this.querySQLiteDb(temps, query);
1666  for (HashMap<String, Object> col : columns) {
1667  if (col.get("name").equals("url")) { //NON-NLS
1668  return true;
1669  }
1670  }
1671 
1672  return false;
1673  }
1674 
1675  @Messages({
1676  "ExtractFavicon_Display_Name=Favicon"
1677  })
1684  private BlackboardArtifact.Type createArtifactType(String artifactName, String displayName) throws TskCoreException {
1685  BlackboardArtifact.Type faviconArtifactType;
1686  try {
1687  faviconArtifactType = tskCase.getBlackboard().getOrAddArtifactType(artifactName, displayName); //NON-NLS
1688  } catch (Blackboard.BlackboardException ex) {
1689  throw new TskCoreException(String.format("An exception was thrown while defining artifact type %s", artifactName), ex);
1690  }
1691  return faviconArtifactType;
1692  }
1693 
1697  private void loadMaliciousChromeExetnsions() {
1698  maliciousChromeExtensions = new HashMap<>();
1699  try {
1700  configExtractor();
1701  String malChromeExtenList = PlatformUtil.getUserConfigDirectory() + File.separator + MALICIOUS_CHROME_EXTENSION_LIST;
1702  BufferedReader csvReader = new BufferedReader(new FileReader(malChromeExtenList));
1703  String row;
1704  while ((row = csvReader.readLine()) != null) {
1705  if (!row.startsWith("#", 0)) {
1706  String[] data = row.split(",");
1707  maliciousChromeExtensions.put(data[0], data[1]);
1708  }
1709  }
1710  } catch (IOException ex) {
1711  logger.log(Level.SEVERE, String.format("Failed to load Malicious Chrome Extension List file (%s)", MALICIOUS_CHROME_EXTENSION_LIST), ex);
1712  }
1713  }
1714 
1720  private void configExtractor() throws IOException {
1721  PlatformUtil.extractResourceToUserConfigDir(Chromium.class,
1722  MALICIOUS_CHROME_EXTENSION_LIST, true);
1723  }
1724 
1725 }

Copyright © 2012-2024 Sleuth Kit Labs. Generated on: Mon Mar 17 2025
This work is licensed under a Creative Commons Attribution-Share Alike 3.0 United States License.