Autopsy  4.21.0
Graphical digital forensics platform for The Sleuth Kit and other tools.
ExtractZoneIdentifier.java
Go to the documentation of this file.
1 /*
2  *
3  * Autopsy Forensic Browser
4  *
5  * Copyright 2019-2021 Basis Technology Corp.
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  * http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  */
19 package org.sleuthkit.autopsy.recentactivity;
20 
21 import java.io.FileNotFoundException;
22 import java.io.IOException;
23 import java.util.ArrayList;
24 import java.util.Collection;
25 import java.util.HashSet;
26 import java.util.List;
27 import java.util.Properties;
28 import java.util.Set;
29 import java.util.logging.Level;
30 import org.openide.util.NbBundle.Messages;
35 import org.sleuthkit.datamodel.AbstractFile;
36 import org.sleuthkit.datamodel.BlackboardArtifact;
37 import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_ASSOCIATED_OBJECT;
38 import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_DOWNLOAD;
39 import org.sleuthkit.datamodel.BlackboardAttribute;
40 import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PATH_ID;
41 import org.sleuthkit.datamodel.Content;
42 import org.sleuthkit.datamodel.ReadContentInputStream;
43 import org.sleuthkit.datamodel.TskCoreException;
44 
50 final class ExtractZoneIdentifier extends Extract {
51 
52  private static final Logger LOG = Logger.getLogger(ExtractEdge.class.getName());
53 
54  private static final String ZONE_IDENTIFIER_FILE = "%:Zone.Identifier"; //NON-NLS
55  private static final String ZONE_IDENTIFIER = ":Zone.Identifier"; //NON-NLS
56  private Content dataSource;
57  private final IngestJobContext context;
58 
59  @Messages({
60  "ExtractZone_displayName= Zone Identifier Analyzer",
61  "ExtractZone_process_errMsg_find=A failure occured while searching for :Zone.Indentifier files.",
62  "ExtractZone_process_errMsg=An error occured processing ':Zone.Indentifier' files.",
63  "ExtractZone_progress_Msg=Extracting :Zone.Identifer files"
64  })
65 
66  ExtractZoneIdentifier(IngestJobContext context) {
67  super(Bundle.ExtractZone_displayName(), context);
68  this.context = context;
69  }
70 
71  @Override
72  void process(Content dataSource, DataSourceIngestModuleProgress progressBar) {
73  this.dataSource = dataSource;
74  progressBar.progress(Bundle.ExtractZone_progress_Msg());
75 
76  List<AbstractFile> zoneFiles = null;
77  try {
78  zoneFiles = currentCase.getServices().getFileManager().findFiles(dataSource, ZONE_IDENTIFIER_FILE);
79  } catch (TskCoreException ex) {
80  addErrorMessage(Bundle.ExtractZone_process_errMsg_find());
81  LOG.log(Level.SEVERE, "Unable to find zone identifier files, exception thrown. ", ex); // NON-NLS
82  }
83 
84  if (zoneFiles == null || zoneFiles.isEmpty()) {
85  return;
86  }
87 
88  Set<Long> knownPathIDs = null;
89  try {
90  knownPathIDs = getPathIDsForType(TSK_WEB_DOWNLOAD);
91  } catch (TskCoreException ex) {
92  addErrorMessage(Bundle.ExtractZone_process_errMsg());
93  LOG.log(Level.SEVERE, "Failed to build PathIDs List for TSK_WEB_DOWNLOAD", ex); // NON-NLS
94  }
95 
96  if (knownPathIDs == null) {
97  return;
98  }
99 
100  Collection<BlackboardArtifact> associatedObjectArtifacts = new ArrayList<>();
101  Collection<BlackboardArtifact> downloadArtifacts = new ArrayList<>();
102 
103  for (AbstractFile zoneFile : zoneFiles) {
104 
105  if (context.dataSourceIngestIsCancelled()) {
106  return;
107  }
108 
109  try {
110  processZoneFile(zoneFile, associatedObjectArtifacts, downloadArtifacts, knownPathIDs);
111  } catch (TskCoreException ex) {
112  addErrorMessage(Bundle.ExtractZone_process_errMsg());
113  String message = String.format("Failed to process zone identifier file %s", zoneFile.getName()); //NON-NLS
114  LOG.log(Level.WARNING, message, ex);
115  }
116  }
117 
118  if (!context.dataSourceIngestIsCancelled()) {
119  postArtifacts(associatedObjectArtifacts);
120  postArtifacts(downloadArtifacts);
121  }
122  }
123 
133  private void processZoneFile(
134  AbstractFile zoneFile, Collection<BlackboardArtifact> associatedObjectArtifacts,
135  Collection<BlackboardArtifact> downloadArtifacts,
136  Set<Long> knownPathIDs) throws TskCoreException {
137 
138  ZoneIdentifierInfo zoneInfo = null;
139 
140  try {
141  zoneInfo = new ZoneIdentifierInfo(zoneFile);
142  } catch (IOException ex) {
143  String message = String.format("Unable to parse temporary File for %s", zoneFile.getName()); //NON-NLS
144  LOG.log(Level.WARNING, message, ex);
145  }
146 
147  if (zoneInfo == null) {
148  return;
149  }
150 
151  AbstractFile downloadFile = getDownloadFile(zoneFile);
152 
153  if (downloadFile != null) {
154  // Only create a new TSK_WEB_DOWNLOAD artifact if one does not exist for downloadFile
155  if (!knownPathIDs.contains(downloadFile.getId())) {
156  // The zone identifier file is the parent of this artifact
157  // because it is the file we parsed to get the data
158  BlackboardArtifact downloadBba = createDownloadArtifact(zoneFile, zoneInfo, downloadFile);
159  downloadArtifacts.add(downloadBba);
160  // create a TSK_ASSOCIATED_OBJECT for the downloaded file, associating it with the TSK_WEB_DOWNLOAD artifact.
161  if (downloadFile.getArtifactsCount(TSK_ASSOCIATED_OBJECT) == 0) {
162  associatedObjectArtifacts.add(createAssociatedArtifact(downloadFile, downloadBba));
163  }
164  }
165 
166  }
167  }
168 
178  private AbstractFile getDownloadFile(AbstractFile zoneFile) throws TskCoreException {
179 
180  String downloadFileName = zoneFile.getName().replace(ZONE_IDENTIFIER, ""); //NON-NLS
181 
182  // The downloaded file should have been added to the database just before the
183  // Zone.Identifier file, possibly with a slack file in between. We will load those files
184  // and test them first since loading files by ID will typically be much faster than
185  // the fallback method of searching by file name.
186  AbstractFile potentialDownloadFile = currentCase.getSleuthkitCase().getAbstractFileById(zoneFile.getId() - 1);
187  if (isZoneFileMatch(zoneFile, downloadFileName, potentialDownloadFile)) {
188  return potentialDownloadFile;
189  }
190  potentialDownloadFile = currentCase.getSleuthkitCase().getAbstractFileById(zoneFile.getId() - 2);
191  if (isZoneFileMatch(zoneFile, downloadFileName, potentialDownloadFile)) {
192  return potentialDownloadFile;
193  }
194 
195  org.sleuthkit.autopsy.casemodule.services.FileManager fileManager = currentCase.getServices().getFileManager();
196  List<AbstractFile> fileList = fileManager.findFilesExactName(zoneFile.getParent().getId(), downloadFileName);
197 
198  for (AbstractFile file : fileList) {
199  if (isZoneFileMatch(zoneFile, downloadFileName, file)) {
200  return file;
201  }
202  }
203 
204  return null;
205  }
206 
219  private boolean isZoneFileMatch(AbstractFile zoneFile, String expectedDownloadFileName, AbstractFile possibleDownloadFile) {
220 
221  if (zoneFile == null || possibleDownloadFile == null || expectedDownloadFileName == null) {
222  return false;
223  }
224 
225  if (zoneFile.getMetaAddr() != possibleDownloadFile.getMetaAddr()) {
226  return false;
227  }
228 
229  if (!expectedDownloadFileName.equals(possibleDownloadFile.getName())) {
230  return false;
231  }
232 
233  if (!possibleDownloadFile.getParentPath().equals(zoneFile.getParentPath())) {
234  return false;
235  }
236 
237  return true;
238  }
239 
249  private BlackboardArtifact createDownloadArtifact(AbstractFile zoneFile, ZoneIdentifierInfo zoneInfo, AbstractFile downloadFile) throws TskCoreException {
250 
251  String downloadFilePath = downloadFile.getParentPath() + downloadFile.getName();
252  long pathID = Util.findID(dataSource, downloadFilePath);
253  Collection<BlackboardAttribute> bbattributes = createDownloadAttributes(
254  downloadFilePath, pathID,
255  zoneInfo.getURL(), null,
256  (zoneInfo.getURL() != null ? NetworkUtils.extractDomain(zoneInfo.getURL()) : ""),
257  null);
258  if (zoneInfo.getZoneIdAsString() != null) {
259  bbattributes.add(new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_COMMENT,
260  RecentActivityExtracterModuleFactory.getModuleName(),
261  zoneInfo.getZoneIdAsString()));
262  }
263  return createArtifactWithAttributes(BlackboardArtifact.Type.TSK_WEB_DOWNLOAD, zoneFile, bbattributes);
264  }
265 
275  private Set<Long> getPathIDsForType(BlackboardArtifact.ARTIFACT_TYPE type) throws TskCoreException {
276  Set<Long> idList = new HashSet<>();
277  for (BlackboardArtifact artifact : currentCase.getSleuthkitCase().getBlackboardArtifacts(type)) {
278  BlackboardAttribute pathIDAttribute = artifact.getAttribute(new BlackboardAttribute.Type(TSK_PATH_ID));
279 
280  if (pathIDAttribute != null) {
281  long contentID = pathIDAttribute.getValueLong();
282  if (contentID != -1) {
283  idList.add(contentID);
284  }
285  }
286  }
287  return idList;
288  }
289 
290  @Messages({
291  "ExtractZone_Local_Machine=Local Machine Zone",
292  "ExtractZone_Local_Intranet=Local Intranet Zone",
293  "ExtractZone_Trusted=Trusted Sites Zone",
294  "ExtractZone_Internet=Internet Zone",
295  "ExtractZone_Restricted=Restricted Sites Zone"
296  })
297 
306  private final static class ZoneIdentifierInfo {
307 
308  private static final String ZONE_ID = "ZoneId"; //NON-NLS
309  private static final String REFERRER_URL = "ReferrerUrl"; //NON-NLS
310  private static final String HOST_URL = "HostUrl"; //NON-NLS
311  private static final String FAMILY_NAME = "LastWriterPackageFamilyName"; //NON-NLS
312  private static String fileName;
313 
314  private final Properties properties = new Properties(null);
315 
325  ZoneIdentifierInfo(AbstractFile zoneFile) throws IOException {
326  fileName = zoneFile.getName();
327  // properties.load will throw IllegalArgument if unicode characters are found in the zone file.
328  try {
329  properties.load(new ReadContentInputStream(zoneFile));
330  } catch (IllegalArgumentException ex) {
331  String message = String.format("Unable to parse Zone Id for File %s", fileName); //NON-NLS
332  LOG.log(Level.WARNING, message);
333  }
334  }
335 
341  private int getZoneId() {
342  int zoneValue = -1;
343  String value = properties.getProperty(ZONE_ID);
344  try {
345  if (value != null) {
346  zoneValue = Integer.parseInt(value);
347  }
348  } catch (NumberFormatException ex) {
349  String message = String.format("Unable to parse Zone Id for File %s", fileName); //NON-NLS
350  LOG.log(Level.WARNING, message);
351  }
352 
353  return zoneValue;
354  }
355 
361  private String getZoneIdAsString() {
362  switch (getZoneId()) {
363  case 0:
364  return Bundle.ExtractZone_Local_Machine();
365  case 1:
366  return Bundle.ExtractZone_Local_Intranet();
367  case 2:
368  return Bundle.ExtractZone_Trusted();
369  case 3:
370  return Bundle.ExtractZone_Internet();
371  case 4:
372  return Bundle.ExtractZone_Restricted();
373  default:
374  return null;
375  }
376  }
377 
383  private String getURL() {
384  return properties.getProperty(HOST_URL);
385  }
386 
392  private String getReferrer() {
393  return properties.getProperty(REFERRER_URL);
394  }
395 
401  private String getFamilyName() {
402  return properties.getProperty(FAMILY_NAME);
403  }
404  }
405 
406 }
List< AbstractFile > findFilesExactName(long parentId, String name)

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