Autopsy  4.19.1
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 
58  @Messages({
59  "ExtractZone_process_errMsg_find=A failure occured while searching for :Zone.Indentifier files.",
60  "ExtractZone_process_errMsg=An error occured processing ':Zone.Indentifier' files.",
61  "ExtractZone_progress_Msg=Extracting :Zone.Identifer files"
62  })
63 
64  @Override
65  void process(Content dataSource, IngestJobContext context, DataSourceIngestModuleProgress progressBar) {
66  this.dataSource = dataSource;
67  progressBar.progress(Bundle.ExtractZone_progress_Msg());
68 
69  List<AbstractFile> zoneFiles = null;
70  try {
71  zoneFiles = currentCase.getServices().getFileManager().findFiles(dataSource, ZONE_IDENTIFIER_FILE);
72  } catch (TskCoreException ex) {
73  addErrorMessage(Bundle.ExtractZone_process_errMsg_find());
74  LOG.log(Level.SEVERE, "Unable to find zone identifier files, exception thrown. ", ex); // NON-NLS
75  }
76 
77  if (zoneFiles == null || zoneFiles.isEmpty()) {
78  return;
79  }
80 
81  Set<Long> knownPathIDs = null;
82  try {
83  knownPathIDs = getPathIDsForType(TSK_WEB_DOWNLOAD);
84  } catch (TskCoreException ex) {
85  addErrorMessage(Bundle.ExtractZone_process_errMsg());
86  LOG.log(Level.SEVERE, "Failed to build PathIDs List for TSK_WEB_DOWNLOAD", ex); // NON-NLS
87  }
88 
89  if (knownPathIDs == null) {
90  return;
91  }
92 
93  Collection<BlackboardArtifact> associatedObjectArtifacts = new ArrayList<>();
94  Collection<BlackboardArtifact> downloadArtifacts = new ArrayList<>();
95 
96  for (AbstractFile zoneFile : zoneFiles) {
97 
98  if (context.dataSourceIngestIsCancelled()) {
99  return;
100  }
101 
102  try {
103  processZoneFile(context, zoneFile, associatedObjectArtifacts, downloadArtifacts, knownPathIDs);
104  } catch (TskCoreException ex) {
105  addErrorMessage(Bundle.ExtractZone_process_errMsg());
106  String message = String.format("Failed to process zone identifier file %s", zoneFile.getName()); //NON-NLS
107  LOG.log(Level.WARNING, message, ex);
108  }
109  }
110 
111  if (!context.dataSourceIngestIsCancelled()) {
112  postArtifacts(associatedObjectArtifacts);
113  postArtifacts(downloadArtifacts);
114  }
115  }
116 
127  private void processZoneFile(IngestJobContext context,
128  AbstractFile zoneFile, Collection<BlackboardArtifact> associatedObjectArtifacts,
129  Collection<BlackboardArtifact> downloadArtifacts,
130  Set<Long> knownPathIDs) throws TskCoreException {
131 
132  ZoneIdentifierInfo zoneInfo = null;
133 
134  try {
135  zoneInfo = new ZoneIdentifierInfo(zoneFile);
136  } catch (IOException ex) {
137  String message = String.format("Unable to parse temporary File for %s", zoneFile.getName()); //NON-NLS
138  LOG.log(Level.WARNING, message, ex);
139  }
140 
141  if (zoneInfo == null) {
142  return;
143  }
144 
145  AbstractFile downloadFile = getDownloadFile(zoneFile);
146 
147  if (downloadFile != null) {
148  // Only create a new TSK_WEB_DOWNLOAD artifact if one does not exist for downloadFile
149  if (!knownPathIDs.contains(downloadFile.getId())) {
150  // The zone identifier file is the parent of this artifact
151  // because it is the file we parsed to get the data
152  BlackboardArtifact downloadBba = createDownloadArtifact(zoneFile, zoneInfo, downloadFile);
153  downloadArtifacts.add(downloadBba);
154  // create a TSK_ASSOCIATED_OBJECT for the downloaded file, associating it with the TSK_WEB_DOWNLOAD artifact.
155  if (downloadFile.getArtifactsCount(TSK_ASSOCIATED_OBJECT) == 0) {
156  associatedObjectArtifacts.add(createAssociatedArtifact(downloadFile, downloadBba));
157  }
158  }
159 
160  }
161  }
162 
172  private AbstractFile getDownloadFile(AbstractFile zoneFile) throws TskCoreException {
173 
174  String downloadFileName = zoneFile.getName().replace(ZONE_IDENTIFIER, ""); //NON-NLS
175 
176  // The downloaded file should have been added to the database just before the
177  // Zone.Identifier file, possibly with a slack file in between. We will load those files
178  // and test them first since loading files by ID will typically be much faster than
179  // the fallback method of searching by file name.
180  AbstractFile potentialDownloadFile = currentCase.getSleuthkitCase().getAbstractFileById(zoneFile.getId() - 1);
181  if (isZoneFileMatch(zoneFile, downloadFileName, potentialDownloadFile)) {
182  return potentialDownloadFile;
183  }
184  potentialDownloadFile = currentCase.getSleuthkitCase().getAbstractFileById(zoneFile.getId() - 2);
185  if (isZoneFileMatch(zoneFile, downloadFileName, potentialDownloadFile)) {
186  return potentialDownloadFile;
187  }
188 
189  org.sleuthkit.autopsy.casemodule.services.FileManager fileManager = currentCase.getServices().getFileManager();
190  List<AbstractFile> fileList = fileManager.findFilesExactName(zoneFile.getParent().getId(), downloadFileName);
191 
192  for (AbstractFile file : fileList) {
193  if (isZoneFileMatch(zoneFile, downloadFileName, file)) {
194  return file;
195  }
196  }
197 
198  return null;
199  }
200 
213  private boolean isZoneFileMatch(AbstractFile zoneFile, String expectedDownloadFileName, AbstractFile possibleDownloadFile) {
214 
215  if (zoneFile == null || possibleDownloadFile == null || expectedDownloadFileName == null) {
216  return false;
217  }
218 
219  if (zoneFile.getMetaAddr() != possibleDownloadFile.getMetaAddr()) {
220  return false;
221  }
222 
223  if (!expectedDownloadFileName.equals(possibleDownloadFile.getName())) {
224  return false;
225  }
226 
227  if (!possibleDownloadFile.getParentPath().equals(zoneFile.getParentPath())) {
228  return false;
229  }
230 
231  return true;
232  }
233 
243  private BlackboardArtifact createDownloadArtifact(AbstractFile zoneFile, ZoneIdentifierInfo zoneInfo, AbstractFile downloadFile) throws TskCoreException {
244 
245  String downloadFilePath = downloadFile.getParentPath() + downloadFile.getName();
246  long pathID = Util.findID(dataSource, downloadFilePath);
247  Collection<BlackboardAttribute> bbattributes = createDownloadAttributes(
248  downloadFilePath, pathID,
249  zoneInfo.getURL(), null,
250  (zoneInfo.getURL() != null ? NetworkUtils.extractDomain(zoneInfo.getURL()) : ""),
251  null);
252  if (zoneInfo.getZoneIdAsString() != null) {
253  bbattributes.add(new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_COMMENT,
254  RecentActivityExtracterModuleFactory.getModuleName(),
255  zoneInfo.getZoneIdAsString()));
256  }
257  return createArtifactWithAttributes(TSK_WEB_DOWNLOAD, zoneFile, bbattributes);
258  }
259 
269  private Set<Long> getPathIDsForType(BlackboardArtifact.ARTIFACT_TYPE type) throws TskCoreException {
270  Set<Long> idList = new HashSet<>();
271  for (BlackboardArtifact artifact : currentCase.getSleuthkitCase().getBlackboardArtifacts(type)) {
272  BlackboardAttribute pathIDAttribute = artifact.getAttribute(new BlackboardAttribute.Type(TSK_PATH_ID));
273 
274  if (pathIDAttribute != null) {
275  long contentID = pathIDAttribute.getValueLong();
276  if (contentID != -1) {
277  idList.add(contentID);
278  }
279  }
280  }
281  return idList;
282  }
283 
284  @Messages({
285  "ExtractZone_Local_Machine=Local Machine Zone",
286  "ExtractZone_Local_Intranet=Local Intranet Zone",
287  "ExtractZone_Trusted=Trusted Sites Zone",
288  "ExtractZone_Internet=Internet Zone",
289  "ExtractZone_Restricted=Restricted Sites Zone"
290  })
291 
300  private final static class ZoneIdentifierInfo {
301 
302  private static final String ZONE_ID = "ZoneId"; //NON-NLS
303  private static final String REFERRER_URL = "ReferrerUrl"; //NON-NLS
304  private static final String HOST_URL = "HostUrl"; //NON-NLS
305  private static final String FAMILY_NAME = "LastWriterPackageFamilyName"; //NON-NLS
306  private static String fileName;
307 
308  private final Properties properties = new Properties(null);
309 
319  ZoneIdentifierInfo(AbstractFile zoneFile) throws IOException {
320  fileName = zoneFile.getName();
321  // properties.load will throw IllegalArgument if unicode characters are found in the zone file.
322  try {
323  properties.load(new ReadContentInputStream(zoneFile));
324  } catch (IllegalArgumentException ex) {
325  String message = String.format("Unable to parse Zone Id for File %s", fileName); //NON-NLS
326  LOG.log(Level.WARNING, message);
327  }
328  }
329 
335  private int getZoneId() {
336  int zoneValue = -1;
337  String value = properties.getProperty(ZONE_ID);
338  try {
339  if (value != null) {
340  zoneValue = Integer.parseInt(value);
341  }
342  } catch (NumberFormatException ex) {
343  String message = String.format("Unable to parse Zone Id for File %s", fileName); //NON-NLS
344  LOG.log(Level.WARNING, message);
345  }
346 
347  return zoneValue;
348  }
349 
355  private String getZoneIdAsString() {
356  switch (getZoneId()) {
357  case 0:
358  return Bundle.ExtractZone_Local_Machine();
359  case 1:
360  return Bundle.ExtractZone_Local_Intranet();
361  case 2:
362  return Bundle.ExtractZone_Trusted();
363  case 3:
364  return Bundle.ExtractZone_Internet();
365  case 4:
366  return Bundle.ExtractZone_Restricted();
367  default:
368  return null;
369  }
370  }
371 
377  private String getURL() {
378  return properties.getProperty(HOST_URL);
379  }
380 
386  private String getReferrer() {
387  return properties.getProperty(REFERRER_URL);
388  }
389 
395  private String getFamilyName() {
396  return properties.getProperty(FAMILY_NAME);
397  }
398  }
399 
400 }
List< AbstractFile > findFilesExactName(long parentId, String name)

Copyright © 2012-2021 Basis Technology. Generated on: Thu Sep 30 2021
This work is licensed under a Creative Commons Attribution-Share Alike 3.0 United States License.