Autopsy  4.15.0
Graphical digital forensics platform for The Sleuth Kit and other tools.
Chrome.java
Go to the documentation of this file.
1 /*
2  *
3  * Autopsy Forensic Browser
4  *
5  * Copyright 2012-2020 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.gson.JsonArray;
26 import com.google.gson.JsonElement;
27 import com.google.gson.JsonIOException;
28 import com.google.gson.JsonObject;
29 import com.google.gson.JsonParser;
30 import com.google.gson.JsonSyntaxException;
31 import org.openide.util.NbBundle;
33 import java.util.logging.Level;
34 import java.util.*;
35 import java.io.File;
36 import java.io.FileNotFoundException;
37 import java.io.FileReader;
38 import java.io.IOException;
39 import org.apache.commons.io.FilenameUtils;
40 import org.openide.util.NbBundle.Messages;
48 import org.sleuthkit.datamodel.AbstractFile;
49 import org.sleuthkit.datamodel.Blackboard;
50 import org.sleuthkit.datamodel.BlackboardArtifact;
51 import org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE;
52 import org.sleuthkit.datamodel.BlackboardAttribute;
53 import org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE;
54 import org.sleuthkit.datamodel.Content;
55 import org.sleuthkit.datamodel.ReadContentInputStream.ReadContentInputStreamException;
56 import org.sleuthkit.datamodel.TskCoreException;
57 import org.sleuthkit.datamodel.TskData;
58 import org.sleuthkit.datamodel.blackboardutils.WebBrowserArtifactsHelper;
59 
63 class Chrome extends Extract {
64 
65  private static final String HISTORY_QUERY = "SELECT urls.url, urls.title, urls.visit_count, urls.typed_count, " //NON-NLS
66  + "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
67  private static final String COOKIE_QUERY = "SELECT name, value, host_key, expires_utc,last_access_utc, creation_utc FROM cookies"; //NON-NLS
68  private static final String DOWNLOAD_QUERY = "SELECT full_path, url, start_time, received_bytes FROM downloads"; //NON-NLS
69  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
70  private static final String LOGIN_QUERY = "SELECT origin_url, username_value, date_created, signon_realm from logins"; //NON-NLS
71  private static final String AUTOFILL_QUERY = "SELECT name, value, count, date_created " +
72  " FROM autofill, autofill_dates " +
73  " WHERE autofill.pair_id = autofill_dates.pair_id"
74  ; //NON-NLS
75  private static final String AUTOFILL_QUERY_V8X = "SELECT name, value, count, date_created, date_last_used from autofill"; //NON-NLS
76  private static final String WEBFORM_ADDRESS_QUERY = "SELECT first_name, middle_name, last_name, address_line_1, address_line_2, city, state, zipcode, country_code, number, email, date_modified " +
77  " FROM autofill_profiles, autofill_profile_names, autofill_profile_emails, autofill_profile_phones" +
78  " WHERE autofill_profiles.guid = autofill_profile_names.guid AND autofill_profiles.guid = autofill_profile_emails.guid AND autofill_profiles.guid = autofill_profile_phones.guid";
79 
80  private static final String WEBFORM_ADDRESS_QUERY_V8X = "SELECT first_name, middle_name, last_name, full_name, street_address, city, state, zipcode, country_code, number, email, date_modified, use_date, use_count" +
81  " FROM autofill_profiles, autofill_profile_names, autofill_profile_emails, autofill_profile_phones" +
82  " WHERE autofill_profiles.guid = autofill_profile_names.guid AND autofill_profiles.guid = autofill_profile_emails.guid AND autofill_profiles.guid = autofill_profile_phones.guid";
83  private final Logger logger = Logger.getLogger(this.getClass().getName());
84  private Content dataSource;
85  private IngestJobContext context;
86 
87  @Messages({
88  "Progress_Message_Chrome_History=Chrome History",
89  "Progress_Message_Chrome_Bookmarks=Chrome Bookmarks",
90  "Progress_Message_Chrome_Cookies=Chrome Cookies",
91  "Progress_Message_Chrome_Downloads=Chrome Downloads",
92  "Progress_Message_Chrome_FormHistory=Chrome Form History",
93  "Progress_Message_Chrome_AutoFill=Chrome Auto Fill",
94  "Progress_Message_Chrome_Logins=Chrome Logins",
95  "Progress_Message_Chrome_Cache=Chrome Cache",
96  })
97 
98  Chrome() {
99  moduleName = NbBundle.getMessage(Chrome.class, "Chrome.moduleName");
100  }
101 
102  @Override
103  public void process(Content dataSource, IngestJobContext context, DataSourceIngestModuleProgress progressBar) {
104  this.dataSource = dataSource;
105  this.context = context;
106  dataFound = false;
107 
108  progressBar.progress(Bundle.Progress_Message_Chrome_History());
109  this.getHistory();
110  if (context.dataSourceIngestIsCancelled()) {
111  return;
112  }
113 
114  progressBar.progress(Bundle.Progress_Message_Chrome_Bookmarks());
115  this.getBookmark();
116  if (context.dataSourceIngestIsCancelled()) {
117  return;
118  }
119 
120  progressBar.progress(Bundle.Progress_Message_Chrome_Cookies());
121  this.getCookie();
122  if (context.dataSourceIngestIsCancelled()) {
123  return;
124  }
125 
126  progressBar.progress(Bundle.Progress_Message_Chrome_Logins());
127  this.getLogins();
128  if (context.dataSourceIngestIsCancelled()) {
129  return;
130  }
131 
132  progressBar.progress(Bundle.Progress_Message_Chrome_AutoFill());
133  this.getAutofill();
134  if (context.dataSourceIngestIsCancelled()) {
135  return;
136  }
137 
138  progressBar.progress(Bundle.Progress_Message_Chrome_Downloads());
139  this.getDownload();
140  if (context.dataSourceIngestIsCancelled()) {
141  return;
142  }
143 
144  progressBar.progress(Bundle.Progress_Message_Chrome_Cache());
145  ChromeCacheExtractor chromeCacheExtractor = new ChromeCacheExtractor(dataSource, context, progressBar);
146  chromeCacheExtractor.processCaches();
147  }
148 
152  private void getHistory() {
153  FileManager fileManager = currentCase.getServices().getFileManager();
154  List<AbstractFile> historyFiles;
155  try {
156  historyFiles = fileManager.findFiles(dataSource, "History", "Chrome"); //NON-NLS
157  } catch (TskCoreException ex) {
158  String msg = NbBundle.getMessage(this.getClass(), "Chrome.getHistory.errMsg.errGettingFiles");
159  logger.log(Level.SEVERE, msg, ex);
160  this.addErrorMessage(this.getName() + ": " + msg);
161  return;
162  }
163 
164  // get only the allocated ones, for now
165  List<AbstractFile> allocatedHistoryFiles = new ArrayList<>();
166  for (AbstractFile historyFile : historyFiles) {
167  if (historyFile.isMetaFlagSet(TskData.TSK_FS_META_FLAG_ENUM.ALLOC)) {
168  allocatedHistoryFiles.add(historyFile);
169  }
170  }
171 
172  // log a message if we don't have any allocated history files
173  if (allocatedHistoryFiles.isEmpty()) {
174  String msg = NbBundle.getMessage(this.getClass(), "Chrome.getHistory.errMsg.couldntFindAnyFiles");
175  logger.log(Level.INFO, msg);
176  return;
177  }
178 
179  dataFound = true;
180  Collection<BlackboardArtifact> bbartifacts = new ArrayList<>();
181  int j = 0;
182  while (j < historyFiles.size()) {
183  String temps = RAImageIngestModule.getRATempPath(currentCase, "chrome") + File.separator + historyFiles.get(j).getName() + j + ".db"; //NON-NLS
184  final AbstractFile historyFile = historyFiles.get(j++);
185  if (historyFile.getSize() == 0) {
186  continue;
187  }
188  try {
189  ContentUtils.writeToFile(historyFile, new File(temps), context::dataSourceIngestIsCancelled);
190  } catch (ReadContentInputStreamException ex) {
191  logger.log(Level.WARNING, String.format("Error reading Chrome web history artifacts file '%s' (id=%d).",
192  historyFile.getName(), historyFile.getId()), ex); //NON-NLS
193  this.addErrorMessage(NbBundle.getMessage(this.getClass(), "Chrome.getHistory.errMsg.errAnalyzingFile",
194  this.getName(), historyFile.getName()));
195  continue;
196  } catch (IOException ex) {
197  logger.log(Level.SEVERE, String.format("Error writing temp sqlite db file '%s' for Chrome web history artifacts file '%s' (id=%d).",
198  temps, historyFile.getName(), historyFile.getId()), ex); //NON-NLS
199  this.addErrorMessage(NbBundle.getMessage(this.getClass(), "Chrome.getHistory.errMsg.errAnalyzingFile",
200  this.getName(), historyFile.getName()));
201  continue;
202  }
203  File dbFile = new File(temps);
204  if (context.dataSourceIngestIsCancelled()) {
205  dbFile.delete();
206  break;
207  }
208  List<HashMap<String, Object>> tempList;
209  tempList = this.dbConnect(temps, HISTORY_QUERY);
210  logger.log(Level.INFO, "{0}- Now getting history from {1} with {2}artifacts identified.", new Object[]{moduleName, temps, tempList.size()}); //NON-NLS
211  for (HashMap<String, Object> result : tempList) {
212  Collection<BlackboardAttribute> bbattributes = new ArrayList<BlackboardAttribute>();
213  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_URL,
214  RecentActivityExtracterModuleFactory.getModuleName(),
215  ((result.get("url").toString() != null) ? result.get("url").toString() : ""))); //NON-NLS
216  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DATETIME_ACCESSED,
217  RecentActivityExtracterModuleFactory.getModuleName(),
218  (Long.valueOf(result.get("last_visit_time").toString()) / 1000000) - Long.valueOf("11644473600"))); //NON-NLS
219  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_REFERRER,
220  RecentActivityExtracterModuleFactory.getModuleName(),
221  ((result.get("from_visit").toString() != null) ? result.get("from_visit").toString() : ""))); //NON-NLS
222  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_TITLE,
223  RecentActivityExtracterModuleFactory.getModuleName(),
224  ((result.get("title").toString() != null) ? result.get("title").toString() : ""))); //NON-NLS
225  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_PROG_NAME,
226  RecentActivityExtracterModuleFactory.getModuleName(),
227  NbBundle.getMessage(this.getClass(), "Chrome.moduleName")));
228  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DOMAIN,
229  RecentActivityExtracterModuleFactory.getModuleName(),
230  (NetworkUtils.extractDomain((result.get("url").toString() != null) ? result.get("url").toString() : "")))); //NON-NLS
231 
232  BlackboardArtifact bbart = createArtifactWithAttributes(ARTIFACT_TYPE.TSK_WEB_HISTORY, historyFile, bbattributes);
233  if (bbart != null) {
234  bbartifacts.add(bbart);
235  }
236  }
237  dbFile.delete();
238  }
239 
240  if( !bbartifacts.isEmpty() ){
241  postArtifacts(bbartifacts);
242  }
243  }
244 
248  private void getBookmark() {
249  FileManager fileManager = currentCase.getServices().getFileManager();
250  List<AbstractFile> bookmarkFiles;
251  try {
252  bookmarkFiles = fileManager.findFiles(dataSource, "Bookmarks", "Chrome"); //NON-NLS
253  } catch (TskCoreException ex) {
254  String msg = NbBundle.getMessage(this.getClass(), "Chrome.getBookmark.errMsg.errGettingFiles");
255  logger.log(Level.SEVERE, msg, ex);
256  this.addErrorMessage(this.getName() + ": " + msg);
257  return;
258  }
259 
260  if (bookmarkFiles.isEmpty()) {
261  logger.log(Level.INFO, "Didn't find any Chrome bookmark files."); //NON-NLS
262  return;
263  }
264 
265  dataFound = true;
266  Collection<BlackboardArtifact> bbartifacts = new ArrayList<>();
267  int j = 0;
268 
269  while (j < bookmarkFiles.size()) {
270  AbstractFile bookmarkFile = bookmarkFiles.get(j++);
271  if (bookmarkFile.getSize() == 0) {
272  continue;
273  }
274  String temps = RAImageIngestModule.getRATempPath(currentCase, "chrome") + File.separator + bookmarkFile.getName() + j + ".db"; //NON-NLS
275  try {
276  ContentUtils.writeToFile(bookmarkFile, new File(temps), context::dataSourceIngestIsCancelled);
277  } catch (ReadContentInputStreamException ex) {
278  logger.log(Level.WARNING, String.format("Error reading Chrome bookmark artifacts file '%s' (id=%d).",
279  bookmarkFile.getName(), bookmarkFile.getId()), ex); //NON-NLS
280  this.addErrorMessage(NbBundle.getMessage(this.getClass(), "Chrome.getBookmark.errMsg.errAnalyzingFile",
281  this.getName(), bookmarkFile.getName()));
282  continue;
283  } catch (IOException ex) {
284  logger.log(Level.SEVERE, String.format("Error writing temp sqlite db file '%s' for Chrome bookmark artifacts file '%s' (id=%d).",
285  temps, bookmarkFile.getName(), bookmarkFile.getId()), ex); //NON-NLS
286  this.addErrorMessage(NbBundle.getMessage(this.getClass(), "Chrome.getBookmark.errMsg.errAnalyzingFile",
287  this.getName(), bookmarkFile.getName()));
288  continue;
289  }
290 
291  logger.log(Level.INFO, "{0}- Now getting Bookmarks from {1}", new Object[]{moduleName, temps}); //NON-NLS
292  File dbFile = new File(temps);
293  if (context.dataSourceIngestIsCancelled()) {
294  dbFile.delete();
295  break;
296  }
297 
298  FileReader tempReader;
299  try {
300  tempReader = new FileReader(temps);
301  } catch (FileNotFoundException ex) {
302  logger.log(Level.WARNING, "Error while trying to read into the Bookmarks for Chrome.", ex); //NON-NLS
303  continue;
304  }
305 
306  final JsonParser parser = new JsonParser();
307  JsonElement jsonElement;
308  JsonObject jElement, jRoot, jBookmark;
309  JsonArray jBookmarkArray;
310 
311  try {
312  jsonElement = parser.parse(tempReader);
313  jElement = jsonElement.getAsJsonObject();
314  jRoot = jElement.get("roots").getAsJsonObject(); //NON-NLS
315  jBookmark = jRoot.get("bookmark_bar").getAsJsonObject(); //NON-NLS
316  jBookmarkArray = jBookmark.getAsJsonArray("children"); //NON-NLS
317  } catch (JsonIOException | JsonSyntaxException | IllegalStateException ex) {
318  logger.log(Level.WARNING, "Error parsing Json from Chrome Bookmark.", ex); //NON-NLS
319  this.addErrorMessage(NbBundle.getMessage(this.getClass(), "Chrome.getBookmark.errMsg.errAnalyzingFile3",
320  this.getName(), bookmarkFile.getName()));
321  continue;
322  }
323 
324  for (JsonElement result : jBookmarkArray) {
325  JsonObject address = result.getAsJsonObject();
326  if (address == null) {
327  continue;
328  }
329  JsonElement urlEl = address.get("url"); //NON-NLS
330  String url;
331  if (urlEl != null) {
332  url = urlEl.getAsString();
333  } else {
334  url = "";
335  }
336  String name;
337  JsonElement nameEl = address.get("name"); //NON-NLS
338  if (nameEl != null) {
339  name = nameEl.getAsString();
340  } else {
341  name = "";
342  }
343  Long date;
344  JsonElement dateEl = address.get("date_added"); //NON-NLS
345  if (dateEl != null) {
346  date = dateEl.getAsLong();
347  } else {
348  date = Long.valueOf(0);
349  }
350  String domain = NetworkUtils.extractDomain(url);
351  try {
352  BlackboardArtifact bbart = bookmarkFile.newArtifact(ARTIFACT_TYPE.TSK_WEB_BOOKMARK);
353  Collection<BlackboardAttribute> bbattributes = new ArrayList<>();
354  //TODO Revisit usage of deprecated constructor as per TSK-583
355  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_URL,
356  RecentActivityExtracterModuleFactory.getModuleName(), url));
357  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_TITLE,
358  RecentActivityExtracterModuleFactory.getModuleName(), name));
359  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DATETIME_CREATED,
360  RecentActivityExtracterModuleFactory.getModuleName(), (date / 1000000) - Long.valueOf("11644473600")));
361  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_PROG_NAME,
362  RecentActivityExtracterModuleFactory.getModuleName(),
363  NbBundle.getMessage(this.getClass(), "Chrome.moduleName")));
364  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DOMAIN,
365  RecentActivityExtracterModuleFactory.getModuleName(), domain));
366  bbart.addAttributes(bbattributes);
367 
368  bbartifacts.add(bbart);
369  } catch (TskCoreException ex) {
370  logger.log(Level.SEVERE, "Error while trying to insert Chrome bookmark artifact{0}", ex); //NON-NLS
371  this.addErrorMessage(
372  NbBundle.getMessage(this.getClass(), "Chrome.getBookmark.errMsg.errAnalyzingFile4",
373  this.getName(), bookmarkFile.getName()));
374  }
375  }
376  postArtifacts(bbartifacts);
377  dbFile.delete();
378  }
379  }
380 
384  private void getCookie() {
385 
386  FileManager fileManager = currentCase.getServices().getFileManager();
387  List<AbstractFile> cookiesFiles;
388  try {
389  cookiesFiles = fileManager.findFiles(dataSource, "Cookies", "Chrome"); //NON-NLS
390  } catch (TskCoreException ex) {
391  String msg = NbBundle.getMessage(this.getClass(), "Chrome.getCookie.errMsg.errGettingFiles");
392  logger.log(Level.SEVERE, msg, ex);
393  this.addErrorMessage(this.getName() + ": " + msg);
394  return;
395  }
396 
397  if (cookiesFiles.isEmpty()) {
398  logger.log(Level.INFO, "Didn't find any Chrome cookies files."); //NON-NLS
399  return;
400  }
401 
402  dataFound = true;
403  Collection<BlackboardArtifact> bbartifacts = new ArrayList<>();
404  int j = 0;
405  while (j < cookiesFiles.size()) {
406  AbstractFile cookiesFile = cookiesFiles.get(j++);
407  if (cookiesFile.getSize() == 0) {
408  continue;
409  }
410  String temps = RAImageIngestModule.getRATempPath(currentCase, "chrome") + File.separator + cookiesFile.getName() + j + ".db"; //NON-NLS
411  try {
412  ContentUtils.writeToFile(cookiesFile, new File(temps), context::dataSourceIngestIsCancelled);
413  } catch (ReadContentInputStreamException ex) {
414  logger.log(Level.WARNING, String.format("Error reading Chrome cookie artifacts file '%s' (id=%d).",
415  cookiesFile.getName(), cookiesFile.getId()), ex); //NON-NLS
416  this.addErrorMessage(NbBundle.getMessage(this.getClass(), "Chrome.getCookie.errMsg.errAnalyzeFile",
417  this.getName(), cookiesFile.getName()));
418  continue;
419  } catch (IOException ex) {
420  logger.log(Level.SEVERE, String.format("Error writing temp sqlite db file '%s' for Chrome cookie artifacts file '%s' (id=%d).",
421  temps, cookiesFile.getName(), cookiesFile.getId()), ex); //NON-NLS
422  this.addErrorMessage(NbBundle.getMessage(this.getClass(), "Chrome.getCookie.errMsg.errAnalyzeFile",
423  this.getName(), cookiesFile.getName()));
424  continue;
425  }
426  File dbFile = new File(temps);
427  if (context.dataSourceIngestIsCancelled()) {
428  dbFile.delete();
429  break;
430  }
431 
432  List<HashMap<String, Object>> tempList = this.dbConnect(temps, COOKIE_QUERY);
433  logger.log(Level.INFO, "{0}- Now getting cookies from {1} with {2}artifacts identified.", new Object[]{moduleName, temps, tempList.size()}); //NON-NLS
434  for (HashMap<String, Object> result : tempList) {
435  Collection<BlackboardAttribute> bbattributes = new ArrayList<>();
436  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_URL,
437  RecentActivityExtracterModuleFactory.getModuleName(),
438  ((result.get("host_key").toString() != null) ? result.get("host_key").toString() : ""))); //NON-NLS
439  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DATETIME,
440  RecentActivityExtracterModuleFactory.getModuleName(),
441  (Long.valueOf(result.get("last_access_utc").toString()) / 1000000) - Long.valueOf("11644473600"))); //NON-NLS
442 
443  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_NAME,
444  RecentActivityExtracterModuleFactory.getModuleName(),
445  ((result.get("name").toString() != null) ? result.get("name").toString() : ""))); //NON-NLS
446  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_VALUE,
447  RecentActivityExtracterModuleFactory.getModuleName(),
448  ((result.get("value").toString() != null) ? result.get("value").toString() : ""))); //NON-NLS
449  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_PROG_NAME,
450  RecentActivityExtracterModuleFactory.getModuleName(),
451  NbBundle.getMessage(this.getClass(), "Chrome.moduleName")));
452  String domain = result.get("host_key").toString(); //NON-NLS
453  domain = domain.replaceFirst("^\\.+(?!$)", "");
454  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DOMAIN,
455  RecentActivityExtracterModuleFactory.getModuleName(), domain));
456 
457  BlackboardArtifact bbart = createArtifactWithAttributes(ARTIFACT_TYPE.TSK_WEB_COOKIE, cookiesFile, bbattributes);
458  if (bbart != null) {
459  bbartifacts.add(bbart);
460  }
461  }
462 
463  dbFile.delete();
464  }
465 
466  if( !bbartifacts.isEmpty() ) {
467  postArtifacts(bbartifacts);
468  }
469  }
470 
474  private void getDownload() {
475  FileManager fileManager = currentCase.getServices().getFileManager();
476  List<AbstractFile> downloadFiles;
477  try {
478  downloadFiles = fileManager.findFiles(dataSource, "History", "Chrome"); //NON-NLS
479  } catch (TskCoreException ex) {
480  String msg = NbBundle.getMessage(this.getClass(), "Chrome.getDownload.errMsg.errGettingFiles");
481  logger.log(Level.SEVERE, msg, ex);
482  this.addErrorMessage(this.getName() + ": " + msg);
483  return;
484  }
485 
486  if (downloadFiles.isEmpty()) {
487  logger.log(Level.INFO, "Didn't find any Chrome download files."); //NON-NLS
488  return;
489  }
490 
491  dataFound = true;
492  Collection<BlackboardArtifact> bbartifacts = new ArrayList<>();
493  int j = 0;
494  while (j < downloadFiles.size()) {
495  AbstractFile downloadFile = downloadFiles.get(j++);
496  if (downloadFile.getSize() == 0) {
497  continue;
498  }
499  String temps = RAImageIngestModule.getRATempPath(currentCase, "chrome") + File.separator + downloadFile.getName() + j + ".db"; //NON-NLS
500  try {
501  ContentUtils.writeToFile(downloadFile, new File(temps), context::dataSourceIngestIsCancelled);
502  } catch (ReadContentInputStreamException ex) {
503  logger.log(Level.WARNING, String.format("Error reading Chrome download artifacts file '%s' (id=%d).",
504  downloadFile.getName(), downloadFile.getId()), ex); //NON-NLS
505  this.addErrorMessage(NbBundle.getMessage(this.getClass(), "Chrome.getDownload.errMsg.errAnalyzeFiles1",
506  this.getName(), downloadFile.getName()));
507  continue;
508  } catch (IOException ex) {
509  logger.log(Level.SEVERE, String.format("Error writing temp sqlite db file '%s' for Chrome download artifacts file '%s' (id=%d).",
510  temps, downloadFile.getName(), downloadFile.getId()), ex); //NON-NLS
511  this.addErrorMessage(NbBundle.getMessage(this.getClass(), "Chrome.getDownload.errMsg.errAnalyzeFiles1",
512  this.getName(), downloadFile.getName()));
513  continue;
514  }
515  File dbFile = new File(temps);
516  if (context.dataSourceIngestIsCancelled()) {
517  dbFile.delete();
518  break;
519  }
520 
521  List<HashMap<String, Object>> tempList;
522 
523  if (isChromePreVersion30(temps)) {
524  tempList = this.dbConnect(temps, DOWNLOAD_QUERY);
525  } else {
526  tempList = this.dbConnect(temps, DOWNLOAD_QUERY_V30);
527  }
528 
529  logger.log(Level.INFO, "{0}- Now getting downloads from {1} with {2} artifacts identified.", new Object[]{moduleName, temps, tempList.size()}); //NON-NLS
530  for (HashMap<String, Object> result : tempList) {
531  Collection<BlackboardAttribute> bbattributes = new ArrayList<>();
532  String fullPath = result.get("full_path").toString(); //NON-NLS
533  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_PATH,
534  RecentActivityExtracterModuleFactory.getModuleName(), fullPath));
535  long pathID = Util.findID(dataSource, fullPath);
536  if (pathID != -1) {
537  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_PATH_ID,
538  NbBundle.getMessage(this.getClass(),
539  "Chrome.parentModuleName"), pathID));
540  }
541  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_URL,
542  RecentActivityExtracterModuleFactory.getModuleName(),
543  ((result.get("url").toString() != null) ? result.get("url").toString() : ""))); //NON-NLS
544  //bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_URL_DECODED.getTypeID(), "Recent Activity", ((result.get("url").toString() != null) ? EscapeUtil.decodeURL(result.get("url").toString()) : "")));
545  Long time = (Long.valueOf(result.get("start_time").toString()) / 1000000) - Long.valueOf("11644473600"); //NON-NLS
546 
547  //TODO Revisit usage of deprecated constructor as per TSK-583
548  //bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_LAST_ACCESSED.getTypeID(), "Recent Activity", "Last Visited", time));
549  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DATETIME_ACCESSED,
550  RecentActivityExtracterModuleFactory.getModuleName(), time));
551  String domain = NetworkUtils.extractDomain((result.get("url").toString() != null) ? result.get("url").toString() : ""); //NON-NLS
552  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DOMAIN,
553  RecentActivityExtracterModuleFactory.getModuleName(), domain));
554  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_PROG_NAME,
555  RecentActivityExtracterModuleFactory.getModuleName(),
556  NbBundle.getMessage(this.getClass(), "Chrome.moduleName")));
557 
558  BlackboardArtifact webDownloadArtifact = createArtifactWithAttributes(ARTIFACT_TYPE.TSK_WEB_DOWNLOAD, downloadFile, bbattributes);
559  if (webDownloadArtifact != null) {
560  bbartifacts.add(webDownloadArtifact);
561 
562  // find the downloaded file and create a TSK_ASSOCIATED_OBJECT for it, associating it with the TSK_WEB_DOWNLOAD artifact.
563  try {
564  String normalizedFullPath = FilenameUtils.normalize(fullPath, true);
565  for (AbstractFile downloadedFile : fileManager.findFiles(dataSource, FilenameUtils.getName(normalizedFullPath), FilenameUtils.getPath(normalizedFullPath))) {
566  BlackboardArtifact associatedObjectArtifact = downloadedFile.newArtifact(BlackboardArtifact.ARTIFACT_TYPE.TSK_ASSOCIATED_OBJECT);
567  associatedObjectArtifact.addAttribute(
568  new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ASSOCIATED_ARTIFACT,
569  RecentActivityExtracterModuleFactory.getModuleName(), webDownloadArtifact.getArtifactID()));
570 
571  bbartifacts.add(associatedObjectArtifact);
572  break;
573  }
574  } catch (TskCoreException ex) {
575  logger.log(Level.SEVERE, String.format("Error creating associated object artifact for file '%s'", fullPath), ex); //NON-NLS
576  }
577  }
578  }
579 
580  dbFile.delete();
581  }
582 
583  if( !bbartifacts.isEmpty() ) {
584  postArtifacts(bbartifacts);
585  }
586  }
587 
591  private void getLogins() {
592 
593  FileManager fileManager = currentCase.getServices().getFileManager();
594  List<AbstractFile> loginDataFiles;
595  try {
596  loginDataFiles = fileManager.findFiles(dataSource, "Login Data", "Chrome"); //NON-NLS
597  } catch (TskCoreException ex) {
598  String msg = NbBundle.getMessage(this.getClass(), "Chrome.getLogin.errMsg.errGettingFiles");
599  logger.log(Level.SEVERE, msg, ex);
600  this.addErrorMessage(this.getName() + ": " + msg);
601  return;
602  }
603 
604  if (loginDataFiles.isEmpty()) {
605  logger.log(Level.INFO, "Didn't find any Chrome Login Data files."); //NON-NLS
606  return;
607  }
608 
609  dataFound = true;
610  Collection<BlackboardArtifact> bbartifacts = new ArrayList<>();
611  int j = 0;
612  while (j < loginDataFiles.size()) {
613  AbstractFile loginDataFile = loginDataFiles.get(j++);
614  if (loginDataFile.getSize() == 0) {
615  continue;
616  }
617  String temps = RAImageIngestModule.getRATempPath(currentCase, "chrome") + File.separator + loginDataFile.getName() + j + ".db"; //NON-NLS
618  try {
619  ContentUtils.writeToFile(loginDataFile, new File(temps), context::dataSourceIngestIsCancelled);
620  } catch (ReadContentInputStreamException ex) {
621  logger.log(Level.WARNING, String.format("Error reading Chrome login artifacts file '%s' (id=%d).",
622  loginDataFile.getName(), loginDataFile.getId()), ex); //NON-NLS
623  this.addErrorMessage(NbBundle.getMessage(this.getClass(), "Chrome.getLogin.errMsg.errAnalyzingFiles",
624  this.getName(), loginDataFile.getName()));
625  continue;
626  } catch (IOException ex) {
627  logger.log(Level.SEVERE, String.format("Error writing temp sqlite db file '%s' for Chrome login artifacts file '%s' (id=%d).",
628  temps, loginDataFile.getName(), loginDataFile.getId()), ex); //NON-NLS
629  this.addErrorMessage(NbBundle.getMessage(this.getClass(), "Chrome.getLogin.errMsg.errAnalyzingFiles",
630  this.getName(), loginDataFile.getName()));
631  continue;
632  }
633  File dbFile = new File(temps);
634  if (context.dataSourceIngestIsCancelled()) {
635  dbFile.delete();
636  break;
637  }
638  List<HashMap<String, Object>> tempList = this.dbConnect(temps, LOGIN_QUERY);
639  logger.log(Level.INFO, "{0}- Now getting login information from {1} with {2}artifacts identified.", new Object[]{moduleName, temps, tempList.size()}); //NON-NLS
640  for (HashMap<String, Object> result : tempList) {
641  Collection<BlackboardAttribute> bbattributes = new ArrayList<>();
642 
643  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_URL,
644  RecentActivityExtracterModuleFactory.getModuleName(),
645  ((result.get("origin_url").toString() != null) ? result.get("origin_url").toString() : ""))); //NON-NLS
646 
647 
648  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DATETIME_CREATED,
649  RecentActivityExtracterModuleFactory.getModuleName(),
650  (Long.valueOf(result.get("date_created").toString()) / 1000000) - Long.valueOf("11644473600"))); //NON-NLS
651 
652  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_URL_DECODED,
653  RecentActivityExtracterModuleFactory.getModuleName(),
654  (NetworkUtils.extractDomain((result.get("origin_url").toString() != null) ? result.get("origin_url").toString() : "")))); //NON-NLS
655 
656  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_USER_NAME,
657  RecentActivityExtracterModuleFactory.getModuleName(),
658  ((result.get("username_value").toString() != null) ? result.get("username_value").toString().replaceAll("'", "''") : ""))); //NON-NLS
659 
660  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DOMAIN,
661  RecentActivityExtracterModuleFactory.getModuleName(),
662  ((result.get("signon_realm").toString() != null) ? result.get("signon_realm").toString() : ""))); //NON-NLS
663 
664  BlackboardArtifact bbart = createArtifactWithAttributes(ARTIFACT_TYPE.TSK_SERVICE_ACCOUNT, loginDataFile, bbattributes);
665  if (bbart != null) {
666  bbartifacts.add(bbart);
667  }
668  }
669 
670  dbFile.delete();
671  }
672 
673  if( !bbartifacts.isEmpty() ) {
674  postArtifacts(bbartifacts);
675  }
676  }
677 
682  private void getAutofill() {
683 
684  FileManager fileManager = currentCase.getServices().getFileManager();
685  List<AbstractFile> webDataFiles;
686  try {
687  webDataFiles = fileManager.findFiles(dataSource, "Web Data", "Chrome"); //NON-NLS
688  } catch (TskCoreException ex) {
689  String msg = NbBundle.getMessage(this.getClass(), "Chrome.getAutofills.errMsg.errGettingFiles");
690  logger.log(Level.SEVERE, msg, ex);
691  this.addErrorMessage(this.getName() + ": " + msg);
692  return;
693  }
694 
695  if (webDataFiles.isEmpty()) {
696  logger.log(Level.INFO, "Didn't find any Chrome Web Data files."); //NON-NLS
697  return;
698  }
699 
700  dataFound = true;
701  Collection<BlackboardArtifact> bbartifacts = new ArrayList<>();
702  int j = 0;
703  while (j < webDataFiles.size()) {
704  AbstractFile webDataFile = webDataFiles.get(j++);
705  if (webDataFile.getSize() == 0) {
706  continue;
707  }
708  String tempFilePath = RAImageIngestModule.getRATempPath(currentCase, "chrome") + File.separator + webDataFile.getName() + j + ".db"; //NON-NLS
709  try {
710  ContentUtils.writeToFile(webDataFile, new File(tempFilePath), context::dataSourceIngestIsCancelled);
711  } catch (ReadContentInputStreamException ex) {
712  logger.log(Level.WARNING, String.format("Error reading Chrome Autofill artifacts file '%s' (id=%d).",
713  webDataFile.getName(), webDataFile.getId()), ex); //NON-NLS
714  this.addErrorMessage(NbBundle.getMessage(this.getClass(), "Chrome.getAutofill.errMsg.errAnalyzingFiles",
715  this.getName(), webDataFile.getName()));
716  continue;
717  } catch (IOException ex) {
718  logger.log(Level.SEVERE, String.format("Error writing temp sqlite db file '%s' for Chrome Web data file '%s' (id=%d).",
719  tempFilePath, webDataFile.getName(), webDataFile.getId()), ex); //NON-NLS
720  this.addErrorMessage(NbBundle.getMessage(this.getClass(), "Chrome.getLogin.errMsg.errAnalyzingFiles",
721  this.getName(), webDataFile.getName()));
722  continue;
723  }
724  File dbFile = new File(tempFilePath);
725  if (context.dataSourceIngestIsCancelled()) {
726  dbFile.delete();
727  break;
728  }
729 
730  // The DB schema is little different in schema version 8x vs older versions
731  boolean isSchemaV8X = Util.checkColumn("date_created", "autofill", tempFilePath);
732 
733  // get form autofill artifacts
734  bbartifacts.addAll(getFormAutofillArtifacts(webDataFile, tempFilePath, isSchemaV8X));
735  try {
736  // get form address atifacts
737  getFormAddressArtifacts(webDataFile, tempFilePath, isSchemaV8X);
738  } catch (NoCurrentCaseException | TskCoreException | Blackboard.BlackboardException ex) {
739  logger.log(Level.SEVERE, String.format("Error adding artifacts to the case database "
740  + "for chrome file %s [objId=%d]", webDataFile.getName(), webDataFile.getId()), ex);
741  }
742 
743  dbFile.delete();
744  }
745 
746  if( !bbartifacts.isEmpty() ){
747  postArtifacts(bbartifacts);
748  }
749  }
750 
760  private Collection<BlackboardArtifact> getFormAutofillArtifacts (AbstractFile webDataFile, String dbFilePath , boolean isSchemaV8X ) {
761 
762  Collection<BlackboardArtifact> bbartifacts = new ArrayList<>();
763 
764  // The DB Schema is little different in version 8x vs older versions
765  String autoFillquery = (isSchemaV8X) ? AUTOFILL_QUERY_V8X
766  : AUTOFILL_QUERY;
767 
768  List<HashMap<String, Object>> autofills = this.dbConnect(dbFilePath, autoFillquery);
769  logger.log(Level.INFO, "{0}- Now getting Autofill information from {1} with {2}artifacts identified.", new Object[]{moduleName, dbFilePath, autofills.size()}); //NON-NLS
770  for (HashMap<String, Object> result : autofills) {
771  Collection<BlackboardAttribute> bbattributes = new ArrayList<>();
772 
773  // extract all common attributes
774  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_NAME,
775  NbBundle.getMessage(this.getClass(), "Chrome.parentModuleName"),
776  ((result.get("name").toString() != null) ? result.get("name").toString() : ""))); //NON-NLS
777 
778  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_VALUE,
779  RecentActivityExtracterModuleFactory.getModuleName(),
780  ((result.get("value").toString() != null) ? result.get("value").toString() : ""))); //NON-NLS
781 
782  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_COUNT,
783  RecentActivityExtracterModuleFactory.getModuleName(),
784  (Integer.valueOf(result.get("count").toString())))); //NON-NLS
785 
786  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DATETIME_CREATED,
787  RecentActivityExtracterModuleFactory.getModuleName(),
788  Long.valueOf(result.get("date_created").toString()))); //NON-NLS
789 
790  // get schema version specific attributes
791  if (isSchemaV8X) {
792  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DATETIME_ACCESSED,
793  RecentActivityExtracterModuleFactory.getModuleName(),
794  Long.valueOf(result.get("date_last_used").toString()))); //NON-NLS
795  }
796 
797  // Add an artifact
798  BlackboardArtifact bbart = createArtifactWithAttributes(ARTIFACT_TYPE.TSK_WEB_FORM_AUTOFILL, webDataFile, bbattributes);
799  if (bbart != null) {
800  bbartifacts.add(bbart);
801  }
802  }
803 
804  // return all extracted artifacts
805  return bbartifacts;
806  }
807 
817  private void getFormAddressArtifacts (AbstractFile webDataFile, String dbFilePath , boolean isSchemaV8X ) throws NoCurrentCaseException,
818  TskCoreException, Blackboard.BlackboardException {
819 
820  String webformAddressQuery = (isSchemaV8X) ? WEBFORM_ADDRESS_QUERY_V8X
821  : WEBFORM_ADDRESS_QUERY;
822 
823  // Helper to create web form address artifacts.
824  WebBrowserArtifactsHelper helper = new WebBrowserArtifactsHelper(
825  Case.getCurrentCaseThrows().getSleuthkitCase(),
826  NbBundle.getMessage(this.getClass(), "Chrome.parentModuleName"),
827  webDataFile
828  );
829 
830  // Get Web form addresses
831  List<HashMap<String, Object>> addresses = this.dbConnect(dbFilePath, webformAddressQuery);
832  logger.log(Level.INFO, "{0}- Now getting Web form addresses from {1} with {2}artifacts identified.", new Object[]{moduleName, dbFilePath, addresses.size()}); //NON-NLS
833  for (HashMap<String, Object> result : addresses) {
834 
835  // get name fields
836  String first_name = result.get("first_name").toString() != null ? result.get("first_name").toString() : "";
837  String middle_name = result.get("middle_name").toString() != null ? result.get("middle_name").toString() : "";
838  String last_name = result.get("last_name").toString() != null ? result.get("last_name").toString() : "";
839 
840  // get email and phone
841  String email_Addr = result.get("email").toString() != null ? result.get("email").toString() : "";
842  String phone_number = result.get("number").toString() != null ? result.get("number").toString() : "";
843 
844  // Get the address fields
845  String city = result.get("city").toString() != null ? result.get("city").toString() : "";
846  String state = result.get("state").toString() != null ? result.get("state").toString() : "";
847  String zipcode = result.get("zipcode").toString() != null ? result.get("zipcode").toString() : "";
848  String country_code = result.get("country_code").toString() != null ? result.get("country_code").toString() : "";
849 
850  // schema version specific fields
851  String full_name = "";
852  String street_address = "";
853  long date_modified = 0;
854  int use_count = 0;
855  long use_date = 0;
856 
857  if (isSchemaV8X) {
858  full_name = result.get("full_name").toString() != null ? result.get("full_name").toString() : "";
859  street_address = result.get("street_address").toString() != null ? result.get("street_address").toString() : "";
860  date_modified = result.get("date_modified").toString() != null ? Long.valueOf(result.get("date_modified").toString()) : 0;
861  use_count = result.get("use_count").toString() != null ? Integer.valueOf(result.get("use_count").toString()) : 0;
862  use_date = result.get("use_date").toString() != null ? Long.valueOf(result.get("use_date").toString()) : 0;
863  } else {
864  String address_line_1 = result.get("address_line_1").toString() != null ? result.get("street_address").toString() : "";
865  String address_line_2 = result.get("address_line_2").toString() != null ? result.get("address_line_2").toString() : "";
866  street_address = String.join(" ", address_line_1, address_line_2);
867  }
868 
869  // Create atrributes from extracted fields
870  if (full_name == null || full_name.isEmpty()) {
871  full_name = String.join(" ", first_name, middle_name, last_name);
872  }
873 
874  String locationAddress = String.join(", ", street_address, city, state, zipcode, country_code);
875 
876  List<BlackboardAttribute> otherAttributes = new ArrayList<>();
877  if (date_modified > 0) {
878  otherAttributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DATETIME_MODIFIED,
879  RecentActivityExtracterModuleFactory.getModuleName(),
880  date_modified)); //NON-NLS
881  }
882 
883  helper.addWebFormAddress(
884  full_name, email_Addr, phone_number,
885  locationAddress, 0, use_date,
886  use_count, otherAttributes);
887  }
888  }
889 
890  private boolean isChromePreVersion30(String temps) {
891  String query = "PRAGMA table_info(downloads)"; //NON-NLS
892  List<HashMap<String, Object>> columns = this.dbConnect(temps, query);
893  for (HashMap<String, Object> col : columns) {
894  if (col.get("name").equals("url")) { //NON-NLS
895  return true;
896  }
897  }
898 
899  return false;
900  }
901 }

Copyright © 2012-2020 Basis Technology. Generated on: Mon Jul 6 2020
This work is licensed under a Creative Commons Attribution-Share Alike 3.0 United States License.