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

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