Autopsy 4.22.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 */
19package org.sleuthkit.autopsy.recentactivity;
20
21import java.io.FileNotFoundException;
22import java.io.IOException;
23import java.util.ArrayList;
24import java.util.Collection;
25import java.util.HashSet;
26import java.util.List;
27import java.util.Properties;
28import java.util.Set;
29import java.util.logging.Level;
30import org.openide.util.NbBundle.Messages;
31import org.sleuthkit.autopsy.coreutils.Logger;
32import org.sleuthkit.autopsy.coreutils.NetworkUtils;
33import org.sleuthkit.autopsy.ingest.DataSourceIngestModuleProgress;
34import org.sleuthkit.autopsy.ingest.IngestJobContext;
35import org.sleuthkit.datamodel.AbstractFile;
36import org.sleuthkit.datamodel.BlackboardArtifact;
37import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_ASSOCIATED_OBJECT;
38import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_DOWNLOAD;
39import org.sleuthkit.datamodel.BlackboardAttribute;
40import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PATH_ID;
41import org.sleuthkit.datamodel.Content;
42import org.sleuthkit.datamodel.ReadContentInputStream;
43import org.sleuthkit.datamodel.TskCoreException;
44
50final 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-2024 Sleuth Kit Labs. Generated on:
This work is licensed under a Creative Commons Attribution-Share Alike 3.0 United States License.