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

Copyright © 2012-2019 Basis Technology. Generated on: Tue Jan 7 2020
This work is licensed under a Creative Commons Attribution-Share Alike 3.0 United States License.