Autopsy  4.19.3
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;
58 import org.sleuthkit.datamodel.AbstractFile;
59 import org.sleuthkit.datamodel.Blackboard;
60 import org.sleuthkit.datamodel.BlackboardArtifact;
61 import org.sleuthkit.datamodel.BlackboardAttribute;
62 import org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE;
63 import org.sleuthkit.datamodel.Content;
64 import org.sleuthkit.datamodel.ReadContentInputStream.ReadContentInputStreamException;
65 import org.sleuthkit.datamodel.Score;
66 import org.sleuthkit.datamodel.TskCoreException;
67 import org.sleuthkit.datamodel.TskData;
68 import org.sleuthkit.datamodel.blackboardutils.WebBrowserArtifactsHelper;
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  continue;
324  }
325  } catch (JsonIOException | JsonSyntaxException | IllegalStateException ex) {
326  logger.log(Level.WARNING, "Error parsing Json from LocalState.", ex); //NON-NLS
327  this.addErrorMessage(NbBundle.getMessage(this.getClass(), "Chrome.getlocalState.errMsg.errAnalyzingFile",
328  this.getDisplayName(), localStateFile.getName()));
329  continue;
330  }
331 
332  BlackboardArtifact.Type localStateArtifactType;
333 
334  try {
335  localStateArtifactType = createArtifactType(LOCAL_STATE_ARTIFACT_NAME, NbBundle.getMessage(this.getClass(), "Chrome.getLocalState.displayName"));
336  } catch (TskCoreException ex) {
337  logger.log(Level.SEVERE, String.format("Error creating artifact type for LocalState."), ex); //NON-NLS
338  this.addErrorMessage(NbBundle.getMessage(this.getClass(), "Chrome.getfavicon.errMsg.errCreateArtifact"));
339  continue;
340 
341  }
342  Set<String> profileNames = jInfoCache.keySet();
343  for (String profileName : profileNames) {
344  JsonElement result = jInfoCache.get(profileName);
345  JsonObject profile = result.getAsJsonObject();
346  if (profile == null) {
347  continue;
348  }
349  JsonElement gaiaIdEl = profile.get("gaia_id"); //NON-NLS
350  String gaiaId;
351  if (gaiaIdEl != null) {
352  gaiaId = gaiaIdEl.getAsString();
353  } else {
354  gaiaId = "";
355  }
356  String hostedDomain;
357  JsonElement hostedDomainEl = profile.get("hosted_domain"); //NON-NLS
358  if (hostedDomainEl != null) {
359  hostedDomain = hostedDomainEl.getAsString();
360  } else {
361  hostedDomain= "";
362  }
363  String shortcutName;
364  JsonElement shortcutNameEl = profile.get("shortcut_name"); //NON-NLS
365  if (shortcutNameEl != null) {
366  shortcutName = shortcutNameEl.getAsString();
367  } else {
368  shortcutName = "";
369  }
370  String name;
371  JsonElement nameEl = profile.get("name"); //NON-NLS
372  if (nameEl != null) {
373  name = nameEl.getAsString();
374  } else {
375  name= "";
376  }
377  String userName;
378  JsonElement userNameEl = profile.get("user_name"); //NON-NLS
379  if (userNameEl != null) {
380  userName = userNameEl.getAsString();
381  } else {
382  userName = "";
383  }
384 
385  if (userName.contains("")) {
386  userProfiles.put(browserLocation + "/" + profileName, name);
387  browserLocations.put(browserLocation + "/" + profileName, browser);
388  } else {
389  userProfiles.put(browserLocation + "/" + profileName, userName);
390  browserLocations.put(browserLocation + "/" + profileName, browser);
391  }
392 
393  Collection<BlackboardAttribute> bbattributes = new ArrayList<>();
394  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_PATH,
395  RecentActivityExtracterModuleFactory.getModuleName(), profileName));
396  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_USER_ID,
397  RecentActivityExtracterModuleFactory.getModuleName(), gaiaId));
398  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DOMAIN,
399  RecentActivityExtracterModuleFactory.getModuleName(), hostedDomain));
400  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_SHORTCUT,
401  RecentActivityExtracterModuleFactory.getModuleName(), shortcutName));
402  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_NAME,
403  RecentActivityExtracterModuleFactory.getModuleName(), name));
404  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_USER_NAME,
405  RecentActivityExtracterModuleFactory.getModuleName(), userName));
406  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_PROG_NAME,
407  RecentActivityExtracterModuleFactory.getModuleName(), browserName));
408 
409  try {
410  bbartifacts.add(createArtifactWithAttributes(localStateArtifactType, localStateFile, bbattributes));
411  } catch (TskCoreException ex) {
412  logger.log(Level.SEVERE, String.format("Failed to create bookmark artifact for file (%d)", localStateFile.getId()), ex);
413  }
414 
415  }
416 
417  if (!context.dataSourceIngestIsCancelled()) {
418  postArtifacts(bbartifacts);
419  }
420  bbartifacts.clear();
421 
422  }
423  // Check if Default, Guest Profile and System Profile are in the usersProfiles, if they are not then add them
424  if (!userProfiles.containsKey("Default")) {
425  userProfiles.put(browserLocation + "/" + "Default", "Default");
426  browserLocations.put(browserLocation + "/" + "Default", browser);
427  }
428  if (!userProfiles.containsKey("Guest Profile")) {
429  userProfiles.put(browserLocation + "/" + "Guest Profile", "Guest");
430  browserLocations.put(browserLocation + "/" + "Guest Profile", browser);
431  }
432  if (!userProfiles.containsKey("System Profile")) {
433  userProfiles.put(browserLocation + "/" + "System Profile", "System");
434  browserLocations.put(browserLocation + "/" + "System Profile", browser);
435  }
436  }
437 
445  private void getExtensions(String browser, String browserLocation, String userName, long ingestJobId) {
446  FileManager fileManager = currentCase.getServices().getFileManager();
447  String browserName = browser;
448  List<AbstractFile> extensionFiles;
449  String extensionsName = EXTENSIONS_FILE_NAME;
450  if (browserName.equals(UC_BROWSER_NAME)) {
451  extensionsName = EXTENSIONS_FILE_NAME + "%";
452  }
453  try {
454  // Local State file is found in the directory about the browserLocation, that is why it is being removed
455  extensionFiles = fileManager.findFiles(dataSource, extensionsName, browserLocation); //NON-NLS
456  } catch (TskCoreException ex) {
457  String msg = NbBundle.getMessage(this.getClass(), "Chrome.getExtensions.errMsg.errGettingFiles");
458  logger.log(Level.SEVERE, msg, ex);
459  this.addErrorMessage(this.getDisplayName() + ": " + msg);
460  return;
461  }
462 
463  // get only the allocated ones, for now
464  List<AbstractFile> allocatedExtensionsFiles = new ArrayList<>();
465  for (AbstractFile extensionFile : extensionFiles) {
466  if (extensionFile.isMetaFlagSet(TskData.TSK_FS_META_FLAG_ENUM.ALLOC)) {
467  allocatedExtensionsFiles.add(extensionFile);
468  }
469  }
470 
471  // log a message if we don't have any allocated Local State files
472  if (allocatedExtensionsFiles.isEmpty()) {
473  String msg = NbBundle.getMessage(this.getClass(), "Chrome.getExtensions.errMsg.couldntFindAnyFiles");
474  logger.log(Level.INFO, msg);
475  return;
476  }
477 
478  dataFound = true;
479  Collection<BlackboardArtifact> bbartifacts = new ArrayList<>();
480  int j = 0;
481  while (j < allocatedExtensionsFiles.size()) {
482  if (browser.contains(GOOGLE_PROFILE_NAME)) {
483  String parentPath = FilenameUtils.normalizeNoEndSeparator(allocatedExtensionsFiles.get(j).getParentPath());
484  browserName = GOOGLE_PROFILE + " " + FilenameUtils.getBaseName(parentPath);
485  }
486  String temps = RAImageIngestModule.getRATempPath(currentCase, browserName, ingestJobId) + File.separator + allocatedExtensionsFiles.get(j).getName() + j; //NON-NLS
487  final AbstractFile extensionFile = allocatedExtensionsFiles.get(j++);
488  if ((extensionFile.getSize() == 0) || (extensionFile.getName().toLowerCase().contains("-slack"))
489  || (extensionFile.getName().toLowerCase().contains("cache")) || (extensionFile.getName().toLowerCase().contains("media"))
490  || (extensionFile.getName().toLowerCase().contains("index"))) {
491  continue;
492  }
493  try {
494  ContentUtils.writeToFile(extensionFile, new File(temps), context::dataSourceIngestIsCancelled);
495  } catch (ReadContentInputStreamException ex) {
496  logger.log(Level.WARNING, String.format("Error reading Chrome web extension artifacts file '%s' (id=%d).",
497  extensionFile.getName(), extensionFile.getId()), ex); //NON-NLS
498  this.addErrorMessage(NbBundle.getMessage(this.getClass(), "Chrome.getExtensions.errMsg.errAnalyzingFile",
499  this.getDisplayName(), extensionFile.getName()));
500  continue;
501  } catch (IOException ex) {
502  logger.log(Level.SEVERE, String.format("Error writing temp file '%s' for Chrome Extensions artifacts file '%s' (id=%d).",
503  temps, extensionFile.getName(), extensionFile.getId()), ex); //NON-NLS
504  this.addErrorMessage(NbBundle.getMessage(this.getClass(), "Chrome.getExtensions.errMsg.errAnalyzingFile",
505  this.getDisplayName(), extensionFile.getName()));
506  continue;
507  }
508 
509  if (context.dataSourceIngestIsCancelled()) {
510  break;
511  }
512 
513  FileReader tempReader;
514  try {
515  tempReader = new FileReader(temps);
516  } catch (FileNotFoundException ex) {
517  logger.log(Level.WARNING, "Error while trying to read into the Secure Preferences file.", ex); //NON-NLS
518  continue;
519  }
520 
521  BlackboardArtifact.Type localStateArtifactType;
522 
523  try {
524  localStateArtifactType = createArtifactType(EXTENSIONS_ARTIFACT_NAME, NbBundle.getMessage(this.getClass(), "Chrome.getExtensions.displayName"));
525  } catch (TskCoreException ex) {
526  logger.log(Level.SEVERE, String.format("Error creating artifact type for Secure Preferences."), ex); //NON-NLS
527  this.addErrorMessage(NbBundle.getMessage(this.getClass(), "Chrome.getExtensions.errMsg.errCreateArtifact"));
528  continue;
529  }
530 
531  String profileName = FilenameUtils.getBaseName(StringUtils.chop(extensionFile.getParentPath()));
532 
533  JsonElement jsonElement;
534  JsonObject jElement, jExtensions, jSettings;
535 
536  try {
537  jsonElement = JsonParser.parseReader(tempReader);
538  jElement = jsonElement.getAsJsonObject();
539  if (jElement.has("extensions")) {
540  logger.log(Level.WARNING, String.format("Processing Secure Preferences from %s", extensionFile.getParentPath()));
541  jExtensions = jElement.get("extensions").getAsJsonObject(); //NON-NLS
542  if (!browserName.equals(OPERA_BROWSER_NAME)) {
543  jSettings = jExtensions.get("settings").getAsJsonObject();
544  } else {
545  jSettings = jExtensions.get("opsettings").getAsJsonObject();
546  }
547  } else {
548  continue;
549  }
550  } catch (JsonIOException | JsonSyntaxException | IllegalStateException ex) {
551  logger.log(Level.WARNING, "Error parsing Json from Secure Preferences.", ex); //NON-NLS
552  this.addErrorMessage(NbBundle.getMessage(this.getClass(), "Chrome.getExtensoins.errMsg.errAnalyzingFile",
553  this.getDisplayName(), extensionFile.getName()));
554  continue;
555  }
556 
557  Set<String> extensions = jSettings.keySet();
558  for (String extension : extensions) {
559  JsonElement result = jSettings.get(extension);
560  JsonObject ext = result.getAsJsonObject();
561  if (ext == null) {
562  continue;
563  }
564  JsonElement flagEl = ext.get("state"); //NON-NLS
565  String flag;
566  if (flagEl != null) {
567  if (flagEl.getAsInt() == 1) {
568  flag = "Enabled";
569  } else {
570  flag = "Disabled";
571  }
572  } else {
573  flag = "";
574  }
575  String apiGrantedPermissions = "";
576  if (ext.has("active_permissions")) {
577  JsonObject permissions = ext.get("active_permissions").getAsJsonObject();
578  JsonArray apiPermissions = permissions.get("api").getAsJsonArray();
579  for (JsonElement apiPermission : apiPermissions) {
580  if (apiPermission.isJsonPrimitive()) {
581  String apigrantEl = apiPermission.getAsString();
582  if (apigrantEl != null) {
583  apiGrantedPermissions = apiGrantedPermissions + ", " + apigrantEl;
584  } else {
585  apiGrantedPermissions = apiGrantedPermissions + "";
586  }
587  }
588  }
589  }
590  String version;
591  String description;
592  String extName;
593  if (ext.has("manifest")) {
594  JsonObject manifest = ext.get("manifest").getAsJsonObject();
595  JsonElement descriptionEl = manifest.get("description");
596  if (descriptionEl != null) {
597  description = descriptionEl.getAsString();
598  } else {
599  description = "";
600  }
601  JsonElement versionEl = manifest.get("version");
602  if (versionEl != null) {
603  version = versionEl.getAsString();
604  } else {
605  version = "";
606  }
607  JsonElement extNameEl = manifest.get("name");
608  if (extNameEl != null) {
609  extName = extNameEl.getAsString();
610  } else {
611  extName = "";
612  }
613  } else {
614  version = "";
615  description = "";
616  extName = "";
617  }
618  BlackboardArtifact art = null;
619  Collection<BlackboardAttribute> bbattributes = new ArrayList<>();
620  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_ID,
621  RecentActivityExtracterModuleFactory.getModuleName(), extension));
622  if (maliciousChromeExtensions.get(extension) != null) {
623  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_COMMENT,
624  RecentActivityExtracterModuleFactory.getModuleName(),
625  MALICIOUS_EXTENSION_FOUND + maliciousChromeExtensions.getOrDefault(extension, "No Source Identified")));
626  }
627  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_NAME,
628  RecentActivityExtracterModuleFactory.getModuleName(), extName));
629  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DESCRIPTION,
630  RecentActivityExtracterModuleFactory.getModuleName(), description));
631  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_VERSION,
632  RecentActivityExtracterModuleFactory.getModuleName(), version));
633  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_FLAG,
634  RecentActivityExtracterModuleFactory.getModuleName(), flag));
635  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_PERMISSIONS,
636  RecentActivityExtracterModuleFactory.getModuleName(), apiGrantedPermissions.replaceFirst(", ", "")));
637  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_USER_NAME,
638  RecentActivityExtracterModuleFactory.getModuleName(), userName));
639  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_PROG_NAME,
640  RecentActivityExtracterModuleFactory.getModuleName(), browserName));
641 
642  try {
643  art = createArtifactWithAttributes(localStateArtifactType, extensionFile, bbattributes);
644  bbartifacts.add(art);
645  } catch (TskCoreException ex) {
646  logger.log(Level.SEVERE, String.format("Failed to create Extension artifact for file (%d)", extensionFile.getId()), ex);
647  }
648  }
649 
650  if (!context.dataSourceIngestIsCancelled()) {
651  postArtifacts(bbartifacts);
652  }
653  bbartifacts.clear();
654 
655  }
656  }
657 
665  private void getHistory(String browser, String browserLocation, String userName, long ingestJobId) {
666  FileManager fileManager = currentCase.getServices().getFileManager();
667  String browserName = browser;
668  List<AbstractFile> historyFiles;
669  String historyFileName = HISTORY_FILE_NAME;
670  if (browserName.equals(UC_BROWSER_NAME)) {
671  historyFileName = HISTORY_FILE_NAME + "%";
672  }
673  try {
674  historyFiles = fileManager.findFiles(dataSource, historyFileName, browserLocation); //NON-NLS
675  } catch (TskCoreException ex) {
676  String msg = NbBundle.getMessage(this.getClass(), "Chrome.getHistory.errMsg.errGettingFiles");
677  logger.log(Level.SEVERE, msg, ex);
678  this.addErrorMessage(this.getDisplayName() + ": " + msg);
679  return;
680  }
681 
682  // get only the allocated ones, for now
683  List<AbstractFile> allocatedHistoryFiles = new ArrayList<>();
684  for (AbstractFile historyFile : historyFiles) {
685  if (historyFile.isMetaFlagSet(TskData.TSK_FS_META_FLAG_ENUM.ALLOC)) {
686  allocatedHistoryFiles.add(historyFile);
687  }
688  }
689 
690  // log a message if we don't have any allocated history files
691  if (allocatedHistoryFiles.isEmpty()) {
692  String msg = NbBundle.getMessage(this.getClass(), "Chrome.getHistory.errMsg.couldntFindAnyFiles");
693  logger.log(Level.INFO, msg);
694  return;
695  }
696 
697  dataFound = true;
698  Collection<BlackboardArtifact> bbartifacts = new ArrayList<>();
699  int j = 0;
700  while (j < allocatedHistoryFiles.size()) {
701  if (browser.contains(GOOGLE_PROFILE_NAME)) {
702  String parentPath = FilenameUtils.normalizeNoEndSeparator(allocatedHistoryFiles.get(j).getParentPath());
703  browserName = GOOGLE_PROFILE + " " + FilenameUtils.getBaseName(parentPath);
704  }
705  String temps = RAImageIngestModule.getRATempPath(currentCase, browserName, ingestJobId) + File.separator + allocatedHistoryFiles.get(j).getName() + j + ".db"; //NON-NLS
706  final AbstractFile historyFile = allocatedHistoryFiles.get(j++);
707  if ((historyFile.getSize() == 0) || (historyFile.getName().toLowerCase().contains("-slack"))
708  || (historyFile.getName().toLowerCase().contains("cache")) || (historyFile.getName().toLowerCase().contains("media"))
709  || (historyFile.getName().toLowerCase().contains("index"))) {
710  continue;
711  }
712  try {
713  ContentUtils.writeToFile(historyFile, new File(temps), context::dataSourceIngestIsCancelled);
714  } catch (ReadContentInputStreamException ex) {
715  logger.log(Level.WARNING, String.format("Error reading Chrome web history artifacts file '%s' (id=%d).",
716  historyFile.getName(), historyFile.getId()), ex); //NON-NLS
717  this.addErrorMessage(NbBundle.getMessage(this.getClass(), "Chrome.getHistory.errMsg.errAnalyzingFile",
718  this.getDisplayName(), historyFile.getName()));
719  continue;
720  } catch (IOException ex) {
721  logger.log(Level.SEVERE, String.format("Error writing temp sqlite db file '%s' for Chrome web history artifacts file '%s' (id=%d).",
722  temps, historyFile.getName(), historyFile.getId()), ex); //NON-NLS
723  this.addErrorMessage(NbBundle.getMessage(this.getClass(), "Chrome.getHistory.errMsg.errAnalyzingFile",
724  this.getDisplayName(), historyFile.getName()));
725  continue;
726  }
727  File dbFile = new File(temps);
728  if (context.dataSourceIngestIsCancelled()) {
729  dbFile.delete();
730  break;
731  }
732  List<HashMap<String, Object>> tempList;
733  tempList = this.querySQLiteDb(temps, HISTORY_QUERY);
734  logger.log(Level.INFO, "{0}- Now getting history from {1} with {2} artifacts identified.", new Object[]{getDisplayName(), temps, tempList.size()}); //NON-NLS
735  for (HashMap<String, Object> result : tempList) {
736  String url = result.get("url") == null ? "" : result.get("url").toString();
737  String extractedDomain = NetworkUtils.extractDomain(url);
738 
739  try {
740  Collection<BlackboardAttribute> bbattributes = createHistoryAttributes(
741  StringUtils.defaultString(url),
742  (Long.valueOf(result.get("last_visit_time").toString()) / 1000000) - Long.valueOf("11644473600"),
743  result.get("from_visit") == null ? "" : result.get("from_visit").toString(),
744  result.get("title") == null ? "" : result.get("title").toString(),
745  browserName,
746  extractedDomain,
747  userName);
748 
749  bbartifacts.add(createArtifactWithAttributes(BlackboardArtifact.Type.TSK_WEB_HISTORY, historyFile, bbattributes));
750  } catch (TskCoreException ex) {
751  logger.log(Level.SEVERE, String.format("Failed to create history artifact for file (%d)", historyFile.getId()), ex);
752  }
753  }
754  dbFile.delete();
755  }
756 
757  if (!bbartifacts.isEmpty() && !context.dataSourceIngestIsCancelled()) {
758  postArtifacts(bbartifacts);
759  }
760  }
761 
769  private void getBookmark(String browser, String browserLocation, String userName, long ingestJobId) {
770  FileManager fileManager = currentCase.getServices().getFileManager();
771  List<AbstractFile> bookmarkFiles;
772  String browserName = browser;
773  String bookmarkFileName = BOOKMARK_FILE_NAME;
774  if (browserName.equals(UC_BROWSER_NAME)) {
775  bookmarkFileName = BOOKMARK_FILE_NAME + "%";
776  }
777  try {
778  bookmarkFiles = fileManager.findFiles(dataSource, bookmarkFileName, browserLocation); //NON-NLS
779  } catch (TskCoreException ex) {
780  String msg = NbBundle.getMessage(this.getClass(), "Chrome.getBookmark.errMsg.errGettingFiles");
781  logger.log(Level.SEVERE, msg, ex);
782  this.addErrorMessage(this.getDisplayName() + ": " + msg);
783  return;
784  }
785 
786  if (bookmarkFiles.isEmpty()) {
787  logger.log(Level.INFO, "Didn't find any Chrome bookmark files."); //NON-NLS
788  return;
789  }
790 
791  dataFound = true;
792  Collection<BlackboardArtifact> bbartifacts = new ArrayList<>();
793  int j = 0;
794  while (j < bookmarkFiles.size()) {
795  if (browser.contains(GOOGLE_PROFILE_NAME)) {
796  String parentPath = FilenameUtils.normalizeNoEndSeparator(bookmarkFiles.get(j).getParentPath());
797  browserName = GOOGLE_PROFILE + " " + FilenameUtils.getBaseName(parentPath);
798  }
799 
800  AbstractFile bookmarkFile = bookmarkFiles.get(j++);
801  if ((bookmarkFile.getSize() == 0) || (bookmarkFile.getName().toLowerCase().contains("-slack"))
802  || (bookmarkFile.getName().toLowerCase().contains("extras")) || (bookmarkFile.getName().toLowerCase().contains("log"))
803  || (bookmarkFile.getName().toLowerCase().contains("backup")) || (bookmarkFile.getName().toLowerCase().contains("visualized"))
804  || (bookmarkFile.getName().toLowerCase().contains("bak")) || (bookmarkFile.getParentPath().toLowerCase().contains("backup"))) {
805  continue;
806  }
807  String temps = RAImageIngestModule.getRATempPath(currentCase, browserName, ingestJobId) + File.separator + bookmarkFile.getName() + j + ".db"; //NON-NLS
808  try {
809  ContentUtils.writeToFile(bookmarkFile, new File(temps), context::dataSourceIngestIsCancelled);
810  } catch (ReadContentInputStreamException ex) {
811  logger.log(Level.WARNING, String.format("Error reading Chrome bookmark artifacts file '%s' (id=%d).",
812  bookmarkFile.getName(), bookmarkFile.getId()), ex); //NON-NLS
813  this.addErrorMessage(NbBundle.getMessage(this.getClass(), "Chrome.getBookmark.errMsg.errAnalyzingFile",
814  this.getDisplayName(), bookmarkFile.getName()));
815  continue;
816  } catch (IOException ex) {
817  logger.log(Level.SEVERE, String.format("Error writing temp sqlite db file '%s' for Chrome bookmark artifacts file '%s' (id=%d).",
818  temps, bookmarkFile.getName(), bookmarkFile.getId()), ex); //NON-NLS
819  this.addErrorMessage(NbBundle.getMessage(this.getClass(), "Chrome.getBookmark.errMsg.errAnalyzingFile",
820  this.getDisplayName(), bookmarkFile.getName()));
821  continue;
822  }
823 
824  logger.log(Level.INFO, "{0}- Now getting Bookmarks from {1}", new Object[]{getDisplayName(), temps}); //NON-NLS
825  File dbFile = new File(temps);
826  if (context.dataSourceIngestIsCancelled()) {
827  dbFile.delete();
828  break;
829  }
830 
831  FileReader tempReader;
832  try {
833  tempReader = new FileReader(temps);
834  } catch (FileNotFoundException ex) {
835  logger.log(Level.WARNING, "Error while trying to read into the Bookmarks for Chrome.", ex); //NON-NLS
836  continue;
837  }
838 
839  JsonElement jsonElement;
840  JsonObject jElement, jRoot;
841 
842  try {
843  jsonElement = JsonParser.parseReader(tempReader);
844  jElement = jsonElement.getAsJsonObject();
845  jRoot = jElement.get("roots").getAsJsonObject(); //NON-NLS
846  Set<String> bookmarkKeys = jRoot.keySet();
847  } catch (JsonIOException | JsonSyntaxException | IllegalStateException ex) {
848  logger.log(Level.WARNING, "Error parsing Json from Chrome Bookmark.", ex); //NON-NLS
849  this.addErrorMessage(NbBundle.getMessage(this.getClass(), "Chrome.getBookmark.errMsg.errAnalyzingFile3",
850  this.getDisplayName(), bookmarkFile.getName()));
851  continue;
852  }
853 
854  Set<String> bookmarkKeys = jRoot.keySet();
855  for (String bookmarkKey : bookmarkKeys) {
856  JsonObject jBookmark = jRoot.get(bookmarkKey).getAsJsonObject(); //NON-NLS
857  JsonArray jBookmarkArray = jBookmark.getAsJsonArray("children"); //NON-NLS
858  for (JsonElement result : jBookmarkArray) {
859  JsonObject address = result.getAsJsonObject();
860  if (address == null) {
861  continue;
862  }
863  JsonElement urlEl = address.get("url"); //NON-NLS
864  String url;
865  if (urlEl != null) {
866  url = urlEl.getAsString();
867  } else {
868  url = "";
869  }
870  String name;
871  JsonElement nameEl = address.get("name"); //NON-NLS
872  if (nameEl != null) {
873  name = nameEl.getAsString();
874  } else {
875  name = "";
876  }
877  Long date;
878  JsonElement dateEl = address.get("date_added"); //NON-NLS
879  if (dateEl != null) {
880  date = dateEl.getAsLong();
881  } else {
882  date = Long.valueOf(0);
883  }
884  String domain = NetworkUtils.extractDomain(url);
885  Collection<BlackboardAttribute> bbattributes = new ArrayList<>();
886  //TODO Revisit usage of deprecated constructor as per TSK-583
887  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_URL,
888  RecentActivityExtracterModuleFactory.getModuleName(), url));
889  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_TITLE,
890  RecentActivityExtracterModuleFactory.getModuleName(), name));
891  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DATETIME_CREATED,
892  RecentActivityExtracterModuleFactory.getModuleName(), (date / 1000000) - Long.valueOf("11644473600")));
893  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_PROG_NAME,
894  RecentActivityExtracterModuleFactory.getModuleName(), browserName));
895  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DOMAIN,
896  RecentActivityExtracterModuleFactory.getModuleName(), domain));
897  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_USER_NAME,
898  RecentActivityExtracterModuleFactory.getModuleName(), userName));
899  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_COMMENT,
900  RecentActivityExtracterModuleFactory.getModuleName(), bookmarkKey));
901 
902 
903  try {
904  bbartifacts.add(createArtifactWithAttributes(BlackboardArtifact.Type.TSK_WEB_BOOKMARK, bookmarkFile, bbattributes));
905  } catch (TskCoreException ex) {
906  logger.log(Level.SEVERE, String.format("Failed to create bookmark artifact for file (%d)", bookmarkFile.getId()), ex);
907  }
908 
909  }
910  }
911 
912  if (!context.dataSourceIngestIsCancelled()) {
913  postArtifacts(bbartifacts);
914  }
915  bbartifacts.clear();
916  dbFile.delete();
917  }
918  }
919 
927  private void getCookie(String browser, String browserLocation, String userName, long ingestJobId) {
928 
929  FileManager fileManager = currentCase.getServices().getFileManager();
930  List<AbstractFile> cookiesFiles;
931  String browserName = browser;
932  String cookieFileName = COOKIE_FILE_NAME;
933  if (browserName.equals(UC_BROWSER_NAME)) {
934  // Wildcard on front and back of Cookies are there for Cookie files that start with something else
935  // ie: UC browser has "Extension Cookies.9" as well as Cookies.9
936  cookieFileName = "%" + COOKIE_FILE_NAME + "%";
937  }
938  try {
939  cookiesFiles = fileManager.findFiles(dataSource, cookieFileName, browserLocation); //NON-NLS
940  } catch (TskCoreException ex) {
941  String msg = NbBundle.getMessage(this.getClass(), "Chrome.getCookie.errMsg.errGettingFiles");
942  logger.log(Level.SEVERE, msg, ex);
943  this.addErrorMessage(this.getDisplayName() + ": " + msg);
944  return;
945  }
946 
947  if (cookiesFiles.isEmpty()) {
948  logger.log(Level.INFO, "Didn't find any Chrome cookies files."); //NON-NLS
949  return;
950  }
951 
952  dataFound = true;
953  Collection<BlackboardArtifact> bbartifacts = new ArrayList<>();
954  int j = 0;
955  while (j < cookiesFiles.size()) {
956  if (browser.contains(GOOGLE_PROFILE_NAME)) {
957  String parentPath = FilenameUtils.normalizeNoEndSeparator(cookiesFiles.get(j).getParentPath());
958  browserName = GOOGLE_PROFILE + FilenameUtils.getBaseName(parentPath);
959  }
960 
961  AbstractFile cookiesFile = cookiesFiles.get(j++);
962  if ((cookiesFile.getSize() == 0) || (cookiesFile.getName().toLowerCase().contains("-slack"))) {
963  continue;
964  }
965  String temps = RAImageIngestModule.getRATempPath(currentCase, browserName, ingestJobId) + File.separator + cookiesFile.getName() + j + ".db"; //NON-NLS
966  try {
967  ContentUtils.writeToFile(cookiesFile, new File(temps), context::dataSourceIngestIsCancelled);
968  } catch (ReadContentInputStreamException ex) {
969  logger.log(Level.WARNING, String.format("Error reading Chrome cookie artifacts file '%s' (id=%d).",
970  cookiesFile.getName(), cookiesFile.getId()), ex); //NON-NLS
971  this.addErrorMessage(NbBundle.getMessage(this.getClass(), "Chrome.getCookie.errMsg.errAnalyzeFile",
972  this.getDisplayName(), cookiesFile.getName()));
973  continue;
974  } catch (IOException ex) {
975  logger.log(Level.SEVERE, String.format("Error writing temp sqlite db file '%s' for Chrome cookie artifacts file '%s' (id=%d).",
976  temps, cookiesFile.getName(), cookiesFile.getId()), ex); //NON-NLS
977  this.addErrorMessage(NbBundle.getMessage(this.getClass(), "Chrome.getCookie.errMsg.errAnalyzeFile",
978  this.getDisplayName(), cookiesFile.getName()));
979  continue;
980  }
981  File dbFile = new File(temps);
982  if (context.dataSourceIngestIsCancelled()) {
983  dbFile.delete();
984  break;
985  }
986 
987  List<HashMap<String, Object>> tempList = this.querySQLiteDb(temps, COOKIE_QUERY);
988  logger.log(Level.INFO, "{0}- Now getting cookies from {1} with {2} artifacts identified.", new Object[]{getDisplayName(), temps, tempList.size()}); //NON-NLS
989  for (HashMap<String, Object> result : tempList) {
990  Collection<BlackboardAttribute> bbattributes = new ArrayList<>();
991  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_URL,
992  RecentActivityExtracterModuleFactory.getModuleName(),
993  ((result.get("host_key").toString() != null) ? result.get("host_key").toString() : ""))); //NON-NLS
994  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DATETIME_ACCESSED,
995  RecentActivityExtracterModuleFactory.getModuleName(),
996  (Long.valueOf(result.get("last_access_utc").toString()) / 1000000) - Long.valueOf("11644473600"))); //NON-NLS
997 
998  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_NAME,
999  RecentActivityExtracterModuleFactory.getModuleName(),
1000  ((result.get("name").toString() != null) ? result.get("name").toString() : ""))); //NON-NLS
1001  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_VALUE,
1002  RecentActivityExtracterModuleFactory.getModuleName(),
1003  ((result.get("value").toString() != null) ? result.get("value").toString() : ""))); //NON-NLS
1004  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_PROG_NAME,
1005  RecentActivityExtracterModuleFactory.getModuleName(), browserName));
1006  String domain = result.get("host_key").toString(); //NON-NLS
1007  domain = domain.replaceFirst("^\\.+(?!$)", "");
1008  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DOMAIN,
1009  RecentActivityExtracterModuleFactory.getModuleName(), domain));
1010  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_USER_NAME,
1011  RecentActivityExtracterModuleFactory.getModuleName(), userName));
1012 
1013  try {
1014  bbartifacts.add(createArtifactWithAttributes(BlackboardArtifact.Type.TSK_WEB_COOKIE, cookiesFile, bbattributes));
1015  } catch (TskCoreException ex) {
1016  logger.log(Level.SEVERE, String.format("Failed to create cookie artifact for file (%d)", cookiesFile.getId()), ex);
1017  }
1018  }
1019 
1020  dbFile.delete();
1021  }
1022 
1023  if (!bbartifacts.isEmpty() && !context.dataSourceIngestIsCancelled()) {
1024  postArtifacts(bbartifacts);
1025  }
1026  }
1027 
1035  private void getDownload(String browser, String browserLocation, String userName, long ingestJobId) {
1036  FileManager fileManager = currentCase.getServices().getFileManager();
1037  List<AbstractFile> downloadFiles;
1038  String browserName = browser;
1039  String historyFileName = HISTORY_FILE_NAME;
1040  if (browserName.equals(UC_BROWSER_NAME)) {
1041  historyFileName = HISTORY_FILE_NAME + "%";
1042  }
1043  try {
1044  downloadFiles = fileManager.findFiles(dataSource, historyFileName, browserLocation); //NON-NLS
1045  } catch (TskCoreException ex) {
1046  String msg = NbBundle.getMessage(this.getClass(), "Chrome.getDownload.errMsg.errGettingFiles");
1047  logger.log(Level.SEVERE, msg, ex);
1048  this.addErrorMessage(this.getDisplayName() + ": " + msg);
1049  return;
1050  }
1051 
1052  if (downloadFiles.isEmpty()) {
1053  logger.log(Level.INFO, "Didn't find any Chrome download files."); //NON-NLS
1054  return;
1055  }
1056 
1057  dataFound = true;
1058  Collection<BlackboardArtifact> bbartifacts = new ArrayList<>();
1059  int j = 0;
1060  while (j < downloadFiles.size()) {
1061  if (browser.contains(GOOGLE_PROFILE_NAME)) {
1062  String parentPath = FilenameUtils.normalizeNoEndSeparator(downloadFiles.get(j).getParentPath());
1063  browserName = GOOGLE_PROFILE + FilenameUtils.getBaseName(parentPath);
1064  }
1065 
1066  AbstractFile downloadFile = downloadFiles.get(j++);
1067  if ((downloadFile.getSize() == 0) || (downloadFile.getName().toLowerCase().contains("-slack"))
1068  || (downloadFile.getName().toLowerCase().contains("cache")) || (downloadFile.getName().toLowerCase().contains("index"))) {
1069  continue;
1070  }
1071 
1072  String temps = RAImageIngestModule.getRATempPath(currentCase, browserName, ingestJobId) + File.separator + downloadFile.getName() + j + ".db"; //NON-NLS
1073  try {
1074  ContentUtils.writeToFile(downloadFile, new File(temps), context::dataSourceIngestIsCancelled);
1075  } catch (ReadContentInputStreamException ex) {
1076  logger.log(Level.WARNING, String.format("Error reading Chrome download artifacts file '%s' (id=%d).",
1077  downloadFile.getName(), downloadFile.getId()), ex); //NON-NLS
1078  this.addErrorMessage(NbBundle.getMessage(this.getClass(), "Chrome.getDownload.errMsg.errAnalyzeFiles1",
1079  this.getDisplayName(), downloadFile.getName()));
1080  continue;
1081  } catch (IOException ex) {
1082  logger.log(Level.SEVERE, String.format("Error writing temp sqlite db file '%s' for Chrome download artifacts file '%s' (id=%d).",
1083  temps, downloadFile.getName(), downloadFile.getId()), ex); //NON-NLS
1084  this.addErrorMessage(NbBundle.getMessage(this.getClass(), "Chrome.getDownload.errMsg.errAnalyzeFiles1",
1085  this.getDisplayName(), downloadFile.getName()));
1086  continue;
1087  }
1088  File dbFile = new File(temps);
1089  if (context.dataSourceIngestIsCancelled()) {
1090  dbFile.delete();
1091  break;
1092  }
1093 
1094  List<HashMap<String, Object>> tempList;
1095 
1096  if (isChromePreVersion30(temps)) {
1097  tempList = this.querySQLiteDb(temps, DOWNLOAD_QUERY);
1098  } else {
1099  tempList = this.querySQLiteDb(temps, DOWNLOAD_QUERY_V30);
1100  }
1101 
1102  logger.log(Level.INFO, "{0}- Now getting downloads from {1} with {2} artifacts identified.", new Object[]{getDisplayName(), temps, tempList.size()}); //NON-NLS
1103  for (HashMap<String, Object> result : tempList) {
1104  Collection<BlackboardAttribute> bbattributes = new ArrayList<>();
1105  String fullPath = result.get("full_path").toString(); //NON-NLS
1106  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_PATH,
1107  RecentActivityExtracterModuleFactory.getModuleName(), fullPath));
1108  long pathID = Util.findID(dataSource, fullPath);
1109  if (pathID != -1) {
1110  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_PATH_ID,
1111  NbBundle.getMessage(this.getClass(),
1112  "Chrome.parentModuleName"), pathID));
1113  }
1114  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_URL,
1115  RecentActivityExtracterModuleFactory.getModuleName(),
1116  ((result.get("url").toString() != null) ? result.get("url").toString() : ""))); //NON-NLS
1117  //bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_URL_DECODED.getTypeID(), "Recent Activity", ((result.get("url").toString() != null) ? EscapeUtil.decodeURL(result.get("url").toString()) : "")));
1118  Long time = (Long.valueOf(result.get("start_time").toString()) / 1000000) - Long.valueOf("11644473600"); //NON-NLS
1119 
1120  //TODO Revisit usage of deprecated constructor as per TSK-583
1121  //bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_LAST_ACCESSED.getTypeID(), "Recent Activity", "Last Visited", time));
1122  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DATETIME_ACCESSED,
1123  RecentActivityExtracterModuleFactory.getModuleName(), time));
1124  String domain = NetworkUtils.extractDomain((result.get("url").toString() != null) ? result.get("url").toString() : ""); //NON-NLS
1125  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DOMAIN,
1126  RecentActivityExtracterModuleFactory.getModuleName(), domain));
1127  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_USER_NAME,
1128  RecentActivityExtracterModuleFactory.getModuleName(), userName));
1129  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_PROG_NAME,
1130  RecentActivityExtracterModuleFactory.getModuleName(), browserName));
1131 
1132  // find the downloaded file and create a TSK_ASSOCIATED_OBJECT for it, associating it with the TSK_WEB_DOWNLOAD artifact.
1133  try {
1134  BlackboardArtifact webDownloadArtifact = createArtifactWithAttributes(BlackboardArtifact.Type.TSK_WEB_DOWNLOAD, downloadFile, bbattributes);
1135  bbartifacts.add(webDownloadArtifact);
1136  String normalizedFullPath = FilenameUtils.normalize(fullPath, true);
1137  for (AbstractFile downloadedFile : currentCase.getSleuthkitCase().getFileManager().findFilesExactNameExactPath(dataSource, FilenameUtils.getName(normalizedFullPath), FilenameUtils.getPath(normalizedFullPath))) {
1138  bbartifacts.add(createAssociatedArtifact(downloadedFile, webDownloadArtifact));
1139  break;
1140  }
1141  } catch (TskCoreException ex) {
1142  logger.log(Level.SEVERE, String.format("Error creating associated object artifact for file '%s'", fullPath), ex); //NON-NLS
1143  }
1144  }
1145 
1146  dbFile.delete();
1147  }
1148 
1149  if (!bbartifacts.isEmpty() && !context.dataSourceIngestIsCancelled()) {
1150  postArtifacts(bbartifacts);
1151  }
1152  }
1153 
1161  private void getFavicons(String browser, String browserLocation, String userName, long ingestJobId) {
1162  FileManager fileManager = currentCase.getServices().getFileManager();
1163  List<AbstractFile> faviconFiles;
1164  String browserName = browser;
1165  try {
1166  faviconFiles = fileManager.findFiles(dataSource, FAVICON_DATA_FILE_NAME, browserLocation); //NON-NLS
1167  } catch (TskCoreException ex) {
1168  String msg = NbBundle.getMessage(this.getClass(), "Chrome.getFavicon.errMsg.errGettingFiles");
1169  logger.log(Level.SEVERE, msg, ex);
1170  this.addErrorMessage(this.getDisplayName() + ": " + msg);
1171  return;
1172  }
1173 
1174  if (faviconFiles.isEmpty()) {
1175  logger.log(Level.INFO, "Didn't find any Chrome favicon files."); //NON-NLS
1176  return;
1177  }
1178 
1179  dataFound = true;
1180  Collection<BlackboardArtifact> bbartifacts = new ArrayList<>();
1181  int j = 0;
1182  while (j < faviconFiles.size()) {
1183  if (browser.contains(GOOGLE_PROFILE_NAME)) {
1184  String parentPath = FilenameUtils.normalizeNoEndSeparator(faviconFiles.get(j).getParentPath());
1185  browserName = GOOGLE_PROFILE + FilenameUtils.getBaseName(parentPath);
1186  }
1187  AbstractFile faviconFile = faviconFiles.get(j++);
1188  if ((faviconFile.getSize() == 0) || (faviconFile.getName().toLowerCase().contains("-slack"))
1189  || (faviconFile.getName().toLowerCase().contains("cache")) || (faviconFile.getName().toLowerCase().contains("index"))) {
1190  continue;
1191  }
1192 
1193  String temps = RAImageIngestModule.getRATempPath(currentCase, browserName, ingestJobId) + File.separator + faviconFile.getName() + j + ".db"; //NON-NLS
1194  try {
1195  ContentUtils.writeToFile(faviconFile, new File(temps), context::dataSourceIngestIsCancelled);
1196  } catch (ReadContentInputStreamException ex) {
1197  logger.log(Level.WARNING, String.format("Error reading Chrome favicons artifacts file '%s' (id=%d).",
1198  faviconFile.getName(), faviconFile.getId()), ex); //NON-NLS
1199  this.addErrorMessage(NbBundle.getMessage(this.getClass(), "Chrome.getFavicon.errMsg.errAnalyzeFiles1",
1200  this.getDisplayName(), faviconFile.getName()));
1201  continue;
1202  } catch (IOException ex) {
1203  logger.log(Level.SEVERE, String.format("Error writing temp sqlite db file '%s' for Chrome favicon artifacts file '%s' (id=%d).",
1204  temps, faviconFile.getName(), faviconFile.getId()), ex); //NON-NLS
1205  this.addErrorMessage(NbBundle.getMessage(this.getClass(), "Chrome.getfavicon.errMsg.errAnalyzeFiles1",
1206  this.getDisplayName(), faviconFile.getName()));
1207  continue;
1208  }
1209  File dbFile = new File(temps);
1210  if (context.dataSourceIngestIsCancelled()) {
1211  dbFile.delete();
1212  break;
1213  }
1214 
1215  BlackboardArtifact.Type faviconArtifactType;
1216 
1217  try {
1218  faviconArtifactType = createArtifactType(FAVICON_ARTIFACT_NAME, NbBundle.getMessage(this.getClass(), "Chrome.getFavicon.displayName"));
1219  } catch (TskCoreException ex) {
1220  logger.log(Level.SEVERE, String.format("Error creating artifact type for Chrome favicon."), ex); //NON-NLS
1221  this.addErrorMessage(NbBundle.getMessage(this.getClass(), "Chrome.getfavicon.errMsg.errCreateArtifact"));
1222  continue;
1223 
1224  }
1225 
1226  List<HashMap<String, Object>> tempList;
1227 
1228  tempList = this.querySQLiteDb(temps, FAVICON_QUERY);
1229 
1230  logger.log(Level.INFO, "{0}- Now getting favicons from {1} with {2} artifacts identified.", new Object[]{getDisplayName(), temps, tempList.size()}); //NON-NLS
1231  for (HashMap<String, Object> result : tempList) {
1232  Collection<BlackboardAttribute> bbattributes = new ArrayList<>();
1233  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_URL,
1234  RecentActivityExtracterModuleFactory.getModuleName(),
1235  ((result.get("page_url").toString() != null) ? result.get("page_url").toString() : ""))); //NON-NLS
1236  Long updatedTime = (Long.valueOf(result.get("last_updated").toString()) / 1000000) - Long.valueOf("11644473600"); //NON-NLS
1237  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DATETIME_MODIFIED,
1238  RecentActivityExtracterModuleFactory.getModuleName(), updatedTime));
1239  Long requestedTime = (Long.valueOf(result.get("last_requested").toString()) / 1000000) - Long.valueOf("11644473600"); //NON-NLS
1240  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DATETIME_ACCESSED,
1241  RecentActivityExtracterModuleFactory.getModuleName(), requestedTime));
1242  String domain = NetworkUtils.extractDomain((result.get("page_url").toString() != null) ? result.get("page_url").toString() : ""); //NON-NLS
1243  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DOMAIN,
1244  RecentActivityExtracterModuleFactory.getModuleName(), domain));
1245  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_USER_NAME,
1246  RecentActivityExtracterModuleFactory.getModuleName(), userName));
1247  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_PROG_NAME,
1248  RecentActivityExtracterModuleFactory.getModuleName(), browserName));
1249 
1250  try {
1251  bbartifacts.add(createArtifactWithAttributes(faviconArtifactType, faviconFile, bbattributes));
1252  } catch (TskCoreException ex) {
1253  logger.log(Level.SEVERE, String.format("Failed to create cookie artifact for file (%d)", faviconFile.getId()), ex);
1254  }
1255 
1256  }
1257 
1258  dbFile.delete();
1259  }
1260 
1261  if (!bbartifacts.isEmpty() && !context.dataSourceIngestIsCancelled()) {
1262  postArtifacts(bbartifacts);
1263  }
1264  }
1265 
1273  private void getLogins(String browser, String browserLocation, String userName, long ingestJobId) {
1274 
1275  FileManager fileManager = currentCase.getServices().getFileManager();
1276  List<AbstractFile> loginDataFiles;
1277  String browserName = browser;
1278  String loginDataFileName = LOGIN_DATA_FILE_NAME;
1279  if (browserName.equals(UC_BROWSER_NAME)) {
1280  loginDataFileName = LOGIN_DATA_FILE_NAME + "%";
1281  }
1282 
1283  try {
1284  loginDataFiles = fileManager.findFiles(dataSource, loginDataFileName, browserLocation); //NON-NLS
1285  } catch (TskCoreException ex) {
1286  String msg = NbBundle.getMessage(this.getClass(), "Chrome.getLogin.errMsg.errGettingFiles");
1287  logger.log(Level.SEVERE, msg, ex);
1288  this.addErrorMessage(this.getDisplayName() + ": " + msg);
1289  return;
1290  }
1291 
1292  if (loginDataFiles.isEmpty()) {
1293  logger.log(Level.INFO, "Didn't find any Chrome Login Data files."); //NON-NLS
1294  return;
1295  }
1296 
1297  dataFound = true;
1298  Collection<BlackboardArtifact> bbartifacts = new ArrayList<>();
1299  int j = 0;
1300  while (j < loginDataFiles.size()) {
1301  if (browser.contains(GOOGLE_PROFILE_NAME)) {
1302  String parentPath = FilenameUtils.normalizeNoEndSeparator(loginDataFiles.get(j).getParentPath());
1303  browserName = GOOGLE_PROFILE + FilenameUtils.getBaseName(parentPath);
1304  }
1305  AbstractFile loginDataFile = loginDataFiles.get(j++);
1306  if ((loginDataFile.getSize() == 0) || (loginDataFile.getName().toLowerCase().contains("-slack"))) {
1307  continue;
1308  }
1309  String temps = RAImageIngestModule.getRATempPath(currentCase, browserName, ingestJobId) + File.separator + loginDataFile.getName() + j + ".db"; //NON-NLS
1310  try {
1311  ContentUtils.writeToFile(loginDataFile, new File(temps), context::dataSourceIngestIsCancelled);
1312  } catch (ReadContentInputStreamException ex) {
1313  logger.log(Level.WARNING, String.format("Error reading Chrome login artifacts file '%s' (id=%d).",
1314  loginDataFile.getName(), loginDataFile.getId()), ex); //NON-NLS
1315  this.addErrorMessage(NbBundle.getMessage(this.getClass(), "Chrome.getLogin.errMsg.errAnalyzingFiles",
1316  this.getDisplayName(), loginDataFile.getName()));
1317  continue;
1318  } catch (IOException ex) {
1319  logger.log(Level.SEVERE, String.format("Error writing temp sqlite db file '%s' for Chrome login artifacts file '%s' (id=%d).",
1320  temps, loginDataFile.getName(), loginDataFile.getId()), ex); //NON-NLS
1321  this.addErrorMessage(NbBundle.getMessage(this.getClass(), "Chrome.getLogin.errMsg.errAnalyzingFiles",
1322  this.getDisplayName(), loginDataFile.getName()));
1323  continue;
1324  }
1325  File dbFile = new File(temps);
1326  if (context.dataSourceIngestIsCancelled()) {
1327  dbFile.delete();
1328  break;
1329  }
1330  List<HashMap<String, Object>> tempList = this.querySQLiteDb(temps, LOGIN_QUERY);
1331  logger.log(Level.INFO, "{0}- Now getting login information from {1} with {2} artifacts identified.", new Object[]{getDisplayName(), temps, tempList.size()}); //NON-NLS
1332  for (HashMap<String, Object> result : tempList) {
1333  Collection<BlackboardAttribute> bbattributes = new ArrayList<>();
1334 
1335  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_URL,
1336  RecentActivityExtracterModuleFactory.getModuleName(),
1337  ((result.get("origin_url").toString() != null) ? result.get("origin_url").toString() : ""))); //NON-NLS
1338 
1339  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DATETIME_CREATED,
1340  RecentActivityExtracterModuleFactory.getModuleName(),
1341  (Long.valueOf(result.get("date_created").toString()) / 1000000) - Long.valueOf("11644473600"))); //NON-NLS
1342 
1343  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_URL_DECODED,
1344  RecentActivityExtracterModuleFactory.getModuleName(),
1345  (NetworkUtils.extractDomain((result.get("origin_url").toString() != null) ? result.get("origin_url").toString() : "")))); //NON-NLS
1346 
1347  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_USER_NAME,
1348  RecentActivityExtracterModuleFactory.getModuleName(),
1349  ((result.get("username_value").toString() != null) ? result.get("username_value").toString().replaceAll("'", "''") : ""))); //NON-NLS
1350 
1351  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_REALM,
1352  RecentActivityExtracterModuleFactory.getModuleName(),
1353  ((result.get("signon_realm") != null && result.get("signon_realm").toString() != null) ? result.get("signon_realm").toString() : ""))); //NON-NLS
1354 
1355  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DOMAIN,
1356  RecentActivityExtracterModuleFactory.getModuleName(),
1357  result.containsKey("signon_realm") ? NetworkUtils.extractDomain(result.get("signon_realm").toString()) : "")); //NON-NLS
1358 
1359  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_PROG_NAME,
1360  RecentActivityExtracterModuleFactory.getModuleName(), browserName));
1361 
1362  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_USER_NAME,
1363  RecentActivityExtracterModuleFactory.getModuleName(), userName));
1364 
1365  try {
1366  bbartifacts.add(createArtifactWithAttributes(BlackboardArtifact.Type.TSK_SERVICE_ACCOUNT, loginDataFile, bbattributes));
1367  } catch (TskCoreException ex) {
1368  logger.log(Level.SEVERE, String.format("Failed to create service account artifact for file (%d)", loginDataFile.getId()), ex);
1369  }
1370  }
1371 
1372  dbFile.delete();
1373  }
1374 
1375  if (!bbartifacts.isEmpty() && !context.dataSourceIngestIsCancelled()) {
1376  postArtifacts(bbartifacts);
1377  }
1378  }
1379 
1388  private void getAutofill(String browser, String browserLocation, String userName, long ingestJobId) {
1389 
1390  FileManager fileManager = currentCase.getServices().getFileManager();
1391  List<AbstractFile> webDataFiles;
1392  String browserName = browser;
1393  String webDataFileName = WEB_DATA_FILE_NAME;
1394  if (browserName.equals(UC_BROWSER_NAME)) {
1395  webDataFileName = WEB_DATA_FILE_NAME + "%";
1396  }
1397 
1398  try {
1399  webDataFiles = fileManager.findFiles(dataSource, webDataFileName, browserLocation); //NON-NLS
1400  } catch (TskCoreException ex) {
1401  String msg = NbBundle.getMessage(this.getClass(), "Chrome.getAutofills.errMsg.errGettingFiles");
1402  logger.log(Level.SEVERE, msg, ex);
1403  this.addErrorMessage(this.getDisplayName() + ": " + msg);
1404  return;
1405  }
1406 
1407  if (webDataFiles.isEmpty()) {
1408  logger.log(Level.INFO, "Didn't find any Chrome Web Data files."); //NON-NLS
1409  return;
1410  }
1411 
1412  dataFound = true;
1413  Collection<BlackboardArtifact> bbartifacts = new ArrayList<>();
1414  int j = 0;
1415  while (j < webDataFiles.size()) {
1416  if (browser.contains(GOOGLE_PROFILE_NAME)) {
1417  String parentPath = FilenameUtils.normalizeNoEndSeparator(webDataFiles.get(j).getParentPath());
1418  browserName = GOOGLE_PROFILE + FilenameUtils.getBaseName(parentPath);
1419  }
1420  databaseEncrypted = false;
1421  AbstractFile webDataFile = webDataFiles.get(j++);
1422  if ((webDataFile.getSize() == 0) || (webDataFile.getName().toLowerCase().contains("-slack"))) {
1423  continue;
1424  }
1425  String tempFilePath = RAImageIngestModule.getRATempPath(currentCase, browserName, ingestJobId) + File.separator + webDataFile.getName() + j + ".db"; //NON-NLS
1426  try {
1427  ContentUtils.writeToFile(webDataFile, new File(tempFilePath), context::dataSourceIngestIsCancelled);
1428  } catch (ReadContentInputStreamException ex) {
1429  logger.log(Level.WARNING, String.format("Error reading Chrome Autofill artifacts file '%s' (id=%d).",
1430  webDataFile.getName(), webDataFile.getId()), ex); //NON-NLS
1431  this.addErrorMessage(NbBundle.getMessage(this.getClass(), "Chrome.getAutofill.errMsg.errAnalyzingFiles",
1432  this.getDisplayName(), webDataFile.getName()));
1433  continue;
1434  } catch (IOException ex) {
1435  logger.log(Level.SEVERE, String.format("Error writing temp sqlite db file '%s' for Chrome Web data file '%s' (id=%d).",
1436  tempFilePath, webDataFile.getName(), webDataFile.getId()), ex); //NON-NLS
1437  this.addErrorMessage(NbBundle.getMessage(this.getClass(), "Chrome.getLogin.errMsg.errAnalyzingFiles",
1438  this.getDisplayName(), webDataFile.getName()));
1439  continue;
1440  }
1441  File dbFile = new File(tempFilePath);
1442  if (context.dataSourceIngestIsCancelled()) {
1443  dbFile.delete();
1444  break;
1445  }
1446 
1447  // The DB schema is little different in schema version 8x vs older versions
1448  boolean isSchemaV8X = Util.checkColumn("date_created", "autofill", tempFilePath);
1449 
1450  // get form autofill artifacts
1451  bbartifacts.addAll(getFormAutofillArtifacts(webDataFile, tempFilePath, isSchemaV8X, userName, browserName));
1452  try {
1453  // get form address atifacts
1454  getFormAddressArtifacts(webDataFile, tempFilePath, isSchemaV8X);
1455  if (databaseEncrypted) {
1456  String comment = String.format("%s Autofill Database Encryption Detected", browserName);
1457  Collection<BlackboardAttribute> bbattributes = Arrays.asList(
1458  new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_COMMENT,
1459  RecentActivityExtracterModuleFactory.getModuleName(), comment));
1460 
1461  bbartifacts.add(
1462  webDataFile.newAnalysisResult(
1463  BlackboardArtifact.Type.TSK_ENCRYPTION_DETECTED, Score.SCORE_NOTABLE,
1464  null, null, comment, bbattributes).getAnalysisResult());
1465  }
1466  } catch (NoCurrentCaseException | TskCoreException | Blackboard.BlackboardException ex) {
1467  logger.log(Level.SEVERE, String.format("Error adding artifacts to the case database "
1468  + "for chrome file %s [objId=%d]", webDataFile.getName(), webDataFile.getId()), ex);
1469  }
1470 
1471  dbFile.delete();
1472  }
1473 
1474  if (!bbartifacts.isEmpty() && !context.dataSourceIngestIsCancelled()) {
1475  postArtifacts(bbartifacts);
1476  }
1477  }
1478 
1489  private Collection<BlackboardArtifact> getFormAutofillArtifacts(AbstractFile webDataFile, String dbFilePath, boolean isSchemaV8X, String userName, String browser) {
1490 
1491  Collection<BlackboardArtifact> bbartifacts = new ArrayList<>();
1492 
1493  // The DB Schema is little different in version 8x vs older versions
1494  String autoFillquery = (isSchemaV8X) ? AUTOFILL_QUERY_V8X
1495  : AUTOFILL_QUERY;
1496 
1497  List<HashMap<String, Object>> autofills = this.querySQLiteDb(dbFilePath, autoFillquery);
1498  logger.log(Level.INFO, "{0}- Now getting Autofill information from {1} with {2} artifacts identified.", new Object[]{getDisplayName(), dbFilePath, autofills.size()}); //NON-NLS
1499  for (HashMap<String, Object> result : autofills) {
1500  Collection<BlackboardAttribute> bbattributes = new ArrayList<>();
1501 
1502  // extract all common attributes
1503  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_NAME,
1504  NbBundle.getMessage(this.getClass(), "Chrome.parentModuleName"),
1505  ((result.get("name").toString() != null) ? result.get("name").toString() : ""))); //NON-NLS
1506 
1507  fieldEncrypted = false;
1508  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_VALUE,
1509  RecentActivityExtracterModuleFactory.getModuleName(),
1510  processFields(result.get("value")))); //NON-NLS
1511 
1512  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_COUNT,
1513  RecentActivityExtracterModuleFactory.getModuleName(),
1514  (Integer.valueOf(result.get("count").toString())))); //NON-NLS
1515 
1516  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DATETIME_CREATED,
1517  RecentActivityExtracterModuleFactory.getModuleName(),
1518  Long.valueOf(result.get("date_created").toString()))); //NON-NLS
1519 
1520  // get schema version specific attributes
1521  if (isSchemaV8X) {
1522  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DATETIME_ACCESSED,
1523  RecentActivityExtracterModuleFactory.getModuleName(),
1524  Long.valueOf(result.get("date_last_used").toString()))); //NON-NLS
1525  }
1526 
1527  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_USER_NAME,
1528  RecentActivityExtracterModuleFactory.getModuleName(), userName));
1529  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_PROG_NAME,
1530  RecentActivityExtracterModuleFactory.getModuleName(), browser));
1531  if (fieldEncrypted) {
1532  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_COMMENT,
1533  RecentActivityExtracterModuleFactory.getModuleName(), ENCRYPTED_FIELD_MESSAGE));
1534  }
1535 
1536  // Add an artifact
1537  try {
1538  bbartifacts.add(createArtifactWithAttributes(BlackboardArtifact.Type.TSK_WEB_FORM_AUTOFILL, webDataFile, bbattributes));
1539  } catch (TskCoreException ex) {
1540  logger.log(Level.SEVERE, String.format("Failed to create web form autopfill artifact for file (%d)", webDataFile.getId()), ex);
1541  }
1542  }
1543 
1544  // return all extracted artifacts
1545  return bbartifacts;
1546  }
1547 
1559  private void getFormAddressArtifacts(AbstractFile webDataFile, String dbFilePath, boolean isSchemaV8X) throws NoCurrentCaseException,
1560  TskCoreException, Blackboard.BlackboardException {
1561 
1562  String webformAddressQuery = (isSchemaV8X) ? WEBFORM_ADDRESS_QUERY_V8X
1563  : WEBFORM_ADDRESS_QUERY;
1564 
1565  // Helper to create web form address artifacts.
1566  WebBrowserArtifactsHelper helper = new WebBrowserArtifactsHelper(
1567  Case.getCurrentCaseThrows().getSleuthkitCase(),
1568  NbBundle.getMessage(this.getClass(), "Chrome.parentModuleName"),
1569  webDataFile, context.getJobId()
1570  );
1571 
1572  // Get Web form addresses
1573  List<HashMap<String, Object>> addresses = this.querySQLiteDb(dbFilePath, webformAddressQuery);
1574  logger.log(Level.INFO, "{0}- Now getting Web form addresses from {1} with {2} artifacts identified.", new Object[]{getDisplayName(), dbFilePath, addresses.size()}); //NON-NLS
1575  for (HashMap<String, Object> result : addresses) {
1576 
1577  fieldEncrypted = false;
1578 
1579  String first_name = processFields(result.get("first_name"));
1580  String middle_name = processFields(result.get("middle_name"));
1581  String last_name = processFields(result.get("last_name"));
1582 
1583  // get email and phone
1584  String email_Addr = processFields(result.get("email"));
1585  String phone_number = processFields(result.get("number"));
1586 
1587  // Get the address fields
1588  String city = processFields(result.get("city"));
1589  String state = processFields(result.get("state"));
1590  String zipcode = processFields(result.get("zipcode"));
1591  String country_code = processFields(result.get("country_code"));
1592 
1593  // schema version specific fields
1594  String full_name = "";
1595  String street_address = "";
1596  long date_modified = 0;
1597  int use_count = 0;
1598  long use_date = 0;
1599 
1600  if (isSchemaV8X) {
1601 
1602  full_name = processFields(result.get("full_name"));
1603  street_address = processFields(result.get("street_address"));
1604  date_modified = result.get("date_modified").toString() != null ? Long.valueOf(result.get("date_modified").toString()) : 0;
1605  use_count = result.get("use_count").toString() != null ? Integer.valueOf(result.get("use_count").toString()) : 0;
1606  use_date = result.get("use_date").toString() != null ? Long.valueOf(result.get("use_date").toString()) : 0;
1607  } else {
1608  String address_line_1 = processFields(result.get("address_line_1"));
1609  String address_line_2 = processFields(result.get("address_line_2"));
1610  street_address = String.join(" ", address_line_1, address_line_2);
1611  }
1612 
1613  // Create atrributes from extracted fields
1614  if (full_name == null || full_name.isEmpty()) {
1615  full_name = String.join(" ", first_name, middle_name, last_name);
1616  }
1617 
1618  String locationAddress = String.join(", ", street_address, city, state, zipcode, country_code);
1619 
1620  List<BlackboardAttribute> otherAttributes = new ArrayList<>();
1621  if (date_modified > 0) {
1622  otherAttributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DATETIME_MODIFIED,
1623  RecentActivityExtracterModuleFactory.getModuleName(),
1624  date_modified)); //NON-NLS
1625  if (fieldEncrypted) {
1626  otherAttributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_COMMENT,
1627  RecentActivityExtracterModuleFactory.getModuleName(), ENCRYPTED_FIELD_MESSAGE)); //NON-NLS
1628 
1629  }
1630  }
1631 
1632  helper.addWebFormAddress(
1633  full_name, email_Addr, phone_number,
1634  locationAddress, 0, use_date,
1635  use_count, otherAttributes);
1636  }
1637  }
1638 
1648  private String processFields(Object dataValue) {
1649 
1650  if (dataValue instanceof byte[]) {
1651  fieldEncrypted = true;
1652  databaseEncrypted = true;
1653  }
1654 
1655  return dataValue.toString() != null ? dataValue.toString() : "";
1656 
1657  }
1658 
1659  private boolean isChromePreVersion30(String temps) {
1660  String query = "PRAGMA table_info(downloads)"; //NON-NLS
1661  List<HashMap<String, Object>> columns = this.querySQLiteDb(temps, query);
1662  for (HashMap<String, Object> col : columns) {
1663  if (col.get("name").equals("url")) { //NON-NLS
1664  return true;
1665  }
1666  }
1667 
1668  return false;
1669  }
1670 
1671  @Messages({
1672  "ExtractFavicon_Display_Name=Favicon"
1673  })
1680  private BlackboardArtifact.Type createArtifactType(String artifactName, String displayName) throws TskCoreException {
1681  BlackboardArtifact.Type faviconArtifactType;
1682  try {
1683  faviconArtifactType = tskCase.getBlackboard().getOrAddArtifactType(artifactName, displayName); //NON-NLS
1684  } catch (Blackboard.BlackboardException ex) {
1685  throw new TskCoreException(String.format("An exception was thrown while defining artifact type %s", artifactName), ex);
1686  }
1687  return faviconArtifactType;
1688  }
1689 
1693  private void loadMaliciousChromeExetnsions() {
1694  maliciousChromeExtensions = new HashMap<>();
1695  try {
1696  configExtractor();
1697  String malChromeExtenList = PlatformUtil.getUserConfigDirectory() + File.separator + MALICIOUS_CHROME_EXTENSION_LIST;
1698  BufferedReader csvReader = new BufferedReader(new FileReader(malChromeExtenList));
1699  String row;
1700  while ((row = csvReader.readLine()) != null) {
1701  if (!row.startsWith("#", 0)) {
1702  String[] data = row.split(",");
1703  maliciousChromeExtensions.put(data[0], data[1]);
1704  }
1705  }
1706  } catch (IOException ex) {
1707  logger.log(Level.SEVERE, String.format("Failed to load Malicious Chrome Extension List file (%s)", MALICIOUS_CHROME_EXTENSION_LIST), ex);
1708  }
1709  }
1710 
1716  private void configExtractor() throws IOException {
1717  PlatformUtil.extractResourceToUserConfigDir(Chromium.class,
1718  MALICIOUS_CHROME_EXTENSION_LIST, true);
1719  }
1720 
1721 }

Copyright © 2012-2022 Basis Technology. Generated on: Tue Jun 27 2023
This work is licensed under a Creative Commons Attribution-Share Alike 3.0 United States License.