From 8e48ac03e68d33d73b4f9d7967a8f493b1891e3a Mon Sep 17 00:00:00 2001 From: Raman Arora Date: Thu, 21 Nov 2019 13:14:25 -0500 Subject: [PATCH] 5780: Context content viewer to show source of message attachments and web downloaded files. - This includes replacing the TSK_DOWNLOAD_SOURCE artifact with TSK_ASSOCIATED_OBJECT artifact, in the RecentActivity module. --- .../autopsy/contentviewers/ContextViewer.form | 95 +++++ .../autopsy/contentviewers/ContextViewer.java | 357 ++++++++++++++++++ .../autopsy/contentviewers/Metadata.java | 21 +- .../autopsy/datamodel/ExtractedContent.java | 4 +- .../autopsy/recentactivity/Chrome.java | 32 +- .../recentactivity/ChromeCacheExtractor.java | 38 +- .../autopsy/recentactivity/ExtractSafari.java | 17 +- .../recentactivity/ExtractZoneIdentifier.java | 63 ++-- .../autopsy/recentactivity/Firefox.java | 63 ++-- 9 files changed, 579 insertions(+), 111 deletions(-) create mode 100644 Core/src/org/sleuthkit/autopsy/contentviewers/ContextViewer.form create mode 100644 Core/src/org/sleuthkit/autopsy/contentviewers/ContextViewer.java diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/ContextViewer.form b/Core/src/org/sleuthkit/autopsy/contentviewers/ContextViewer.form new file mode 100644 index 0000000000..c7f826dc9e --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/ContextViewer.form @@ -0,0 +1,95 @@ + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/ContextViewer.java b/Core/src/org/sleuthkit/autopsy/contentviewers/ContextViewer.java new file mode 100644 index 0000000000..3c2e4e526f --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/ContextViewer.java @@ -0,0 +1,357 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2019 Basis Technology Corp. + * Contact: carrier sleuthkit org + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.sleuthkit.autopsy.contentviewers; + +import java.awt.Component; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.logging.Level; +import org.apache.commons.lang.StringUtils; +import org.openide.nodes.Node; +import org.openide.util.NbBundle; +import org.openide.util.lookup.ServiceProvider; +import org.sleuthkit.autopsy.casemodule.Case; +import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; +import org.sleuthkit.autopsy.corecomponentinterfaces.DataContentViewer; +import org.sleuthkit.autopsy.coreutils.Logger; +import org.sleuthkit.autopsy.directorytree.DirectoryTreeTopComponent; +import org.sleuthkit.datamodel.AbstractFile; +import org.sleuthkit.datamodel.BlackboardArtifact; +import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_ASSOCIATED_OBJECT; +import org.sleuthkit.datamodel.BlackboardAttribute; +import org.sleuthkit.datamodel.SleuthkitCase; +import org.sleuthkit.datamodel.TskCoreException; + +/** + * Displays additional context for the selected file, such as its source, and + * usage, if known. + * + */ +@ServiceProvider(service = DataContentViewer.class, position = 7) +@NbBundle.Messages({ + "ContextViewer.title=Context Viewer", + "ContextViewer.toolTip=Displays context for selected file." +}) +public final class ContextViewer extends javax.swing.JPanel implements DataContentViewer { + + private static final long serialVersionUID = 1L; + private static final Logger logger = Logger.getLogger(ContextViewer.class.getName()); + + // defines a list of artifacts that provide context for a file + private static final List SOURCE_CONTEXT_ARTIFACTS = new ArrayList<>(); + + static { + SOURCE_CONTEXT_ARTIFACTS.add(TSK_ASSOCIATED_OBJECT); + } + + private BlackboardArtifact sourceContextArtifact; + + /** + * Creates new form ContextViewer + */ + public ContextViewer() { + + initComponents(); + } + + /** + * This method is called from within the constructor to initialize the form. + * WARNING: Do NOT modify this code. The content of this method is always + * regenerated by the Form Editor. + */ + @SuppressWarnings("unchecked") + // //GEN-BEGIN:initComponents + private void initComponents() { + + jSourceGoToResultButton = new javax.swing.JButton(); + jLabel1 = new javax.swing.JLabel(); + jSourceNameLabel = new javax.swing.JLabel(); + jSourceTextLabel = new javax.swing.JLabel(); + + org.openide.awt.Mnemonics.setLocalizedText(jSourceGoToResultButton, org.openide.util.NbBundle.getMessage(ContextViewer.class, "ContextViewer.jSourceGoToResultButton.text")); // NOI18N + jSourceGoToResultButton.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + jSourceGoToResultButtonActionPerformed(evt); + } + }); + + jLabel1.setFont(new java.awt.Font("Dialog", 1, 14)); // NOI18N + org.openide.awt.Mnemonics.setLocalizedText(jLabel1, org.openide.util.NbBundle.getMessage(ContextViewer.class, "ContextViewer.jLabel1.text")); // NOI18N + + org.openide.awt.Mnemonics.setLocalizedText(jSourceNameLabel, org.openide.util.NbBundle.getMessage(ContextViewer.class, "ContextViewer.jSourceNameLabel.text")); // NOI18N + + org.openide.awt.Mnemonics.setLocalizedText(jSourceTextLabel, org.openide.util.NbBundle.getMessage(ContextViewer.class, "ContextViewer.jSourceTextLabel.text")); // NOI18N + + javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); + this.setLayout(layout); + layout.setHorizontalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addContainerGap() + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(jLabel1) + .addGroup(layout.createSequentialGroup() + .addGap(6, 6, 6) + .addComponent(jSourceNameLabel) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(jSourceTextLabel, javax.swing.GroupLayout.DEFAULT_SIZE, 192, Short.MAX_VALUE))) + .addGap(36, 36, 36)) + .addGroup(layout.createSequentialGroup() + .addComponent(jSourceGoToResultButton) + .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)))) + ); + layout.setVerticalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addContainerGap() + .addComponent(jLabel1) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(jSourceNameLabel) + .addComponent(jSourceTextLabel)) + .addGap(18, 18, 18) + .addComponent(jSourceGoToResultButton) + .addGap(0, 203, Short.MAX_VALUE)) + ); + }// //GEN-END:initComponents + + private void jSourceGoToResultButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jSourceGoToResultButtonActionPerformed + + final DirectoryTreeTopComponent dtc = DirectoryTreeTopComponent.findInstance(); + + // Navigate to the source context artifact. + if (sourceContextArtifact != null) { + dtc.viewArtifact(sourceContextArtifact); + } + + }//GEN-LAST:event_jSourceGoToResultButtonActionPerformed + + @Override + public void setNode(Node selectedNode) { + if ((selectedNode == null) || (!isSupported(selectedNode))) { + resetComponent(); + return; + } + + AbstractFile file = selectedNode.getLookup().lookup(AbstractFile.class); + try { + populateSourceContextData(file); + } catch (NoCurrentCaseException | TskCoreException ex) { + logger.log(Level.SEVERE, "Exception displaying context for file {0}", file); //NON-NLS + } + } + + @Override + public String getTitle() { + return Bundle.ContextViewer_title(); + } + + @Override + public String getToolTip() { + return Bundle.ContextViewer_toolTip(); + } + + @Override + public DataContentViewer createInstance() { + return new ContextViewer(); + } + + @Override + public Component getComponent() { + return this; + } + + @Override + public void resetComponent() { + setSourceName(""); + setSourceText(""); + } + + @Override + public boolean isSupported(Node node) { + + // check if the node has an abstract file and the file has any context defining artifacts. + if (node.getLookup().lookup(AbstractFile.class) != null) { + AbstractFile abstractFile = node.getLookup().lookup(AbstractFile.class); + for (BlackboardArtifact.ARTIFACT_TYPE artifactType : SOURCE_CONTEXT_ARTIFACTS) { + List artifactsList; + try { + artifactsList = abstractFile.getArtifacts(artifactType); + if (!artifactsList.isEmpty()) { + return true; + } + } catch (TskCoreException ex) { + logger.log(Level.SEVERE, "Exception while looking up context artifacts for file {0}", abstractFile); //NON-NLS + } + } + + } + + return false; + } + + @Override + public int isPreferred(Node node) { + return 1; + } + + private void populateSourceContextData(AbstractFile sourceFile) throws NoCurrentCaseException, TskCoreException { + + SleuthkitCase tskCase = Case.getCurrentCaseThrows().getSleuthkitCase(); + + // Check for all context artifacts + boolean foundASource = false; + for (BlackboardArtifact.ARTIFACT_TYPE artifactType : SOURCE_CONTEXT_ARTIFACTS) { + List artifactsList = tskCase.getBlackboardArtifacts(artifactType, sourceFile.getId()); + if (!artifactsList.isEmpty()) { + foundASource = true; + } + for (BlackboardArtifact contextArtifact : artifactsList) { + addSourceEntry(contextArtifact); + } + } + if (foundASource == false) { + setSourceName("Unknown"); + showSourceText(false); + } + } + + @NbBundle.Messages({ + "ContextViewer.attachmentSource=Attached to: ", + "ContextViewer.downloadSource=Downloaded from: " + }) + private void addSourceEntry(BlackboardArtifact artifact) throws TskCoreException { + + if (BlackboardArtifact.ARTIFACT_TYPE.TSK_ASSOCIATED_OBJECT.getTypeID() == artifact.getArtifactTypeID()) { + BlackboardAttribute associatedArtifactAttribute = artifact.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ASSOCIATED_ARTIFACT)); + if (associatedArtifactAttribute != null) { + long artifactId = associatedArtifactAttribute.getValueLong(); + BlackboardArtifact associatedArtifact = artifact.getSleuthkitCase().getBlackboardArtifact(artifactId); + + //save the artifact id for "Go to Result" button + sourceContextArtifact = associatedArtifact; + + if (BlackboardArtifact.ARTIFACT_TYPE.TSK_MESSAGE.getTypeID() == associatedArtifact.getArtifactTypeID() + || BlackboardArtifact.ARTIFACT_TYPE.TSK_EMAIL_MSG.getTypeID() == associatedArtifact.getArtifactTypeID()) { + + setSourceName(Bundle.ContextViewer_attachmentSource()); + setSourceText(msgArtifactToAbbreiviatedString(associatedArtifact)); + + } else if (BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_DOWNLOAD.getTypeID() == associatedArtifact.getArtifactTypeID() + || BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_CACHE.getTypeID() == associatedArtifact.getArtifactTypeID()) { + + setSourceName(Bundle.ContextViewer_downloadSource()); + setSourceText(webDownloadArtifactToString(associatedArtifact)); + } + } + } + + } + + private void setSourceName(String nameLabel) { + jSourceNameLabel.setText(nameLabel); + } + + private void setSourceText(String text) { + jSourceTextLabel.setText(text); + showSourceText(true); + } + + private void showSourceText(boolean isVisible) { + jSourceTextLabel.setVisible(isVisible); + } + + private String webDownloadArtifactToString(BlackboardArtifact artifact) throws TskCoreException { + StringBuilder sb = new StringBuilder(1024); + Map attributesMap = getAttributesMap(artifact); + + if (BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_DOWNLOAD.getTypeID() == artifact.getArtifactTypeID() + || BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_CACHE.getTypeID() == artifact.getArtifactTypeID()) { + appendAttributeString(sb, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_URL, attributesMap, "URL"); + appendAttributeString(sb, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME_CREATED, attributesMap, "On"); + } + return sb.toString(); + } + + private String msgArtifactToAbbreiviatedString(BlackboardArtifact artifact) throws TskCoreException { + + StringBuilder sb = new StringBuilder(1024); + Map attributesMap = getAttributesMap(artifact); + + if (BlackboardArtifact.ARTIFACT_TYPE.TSK_MESSAGE.getTypeID() == artifact.getArtifactTypeID()) { + sb.append("Message "); + appendAttributeString(sb, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PHONE_NUMBER_FROM, attributesMap, "From"); + appendAttributeString(sb, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PHONE_NUMBER_TO, attributesMap, "To"); + appendAttributeString(sb, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME, attributesMap, "On"); + } else if (BlackboardArtifact.ARTIFACT_TYPE.TSK_EMAIL_MSG.getTypeID() == artifact.getArtifactTypeID()) { + sb.append("Email "); + appendAttributeString(sb, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_EMAIL_FROM, attributesMap, "From"); + appendAttributeString(sb, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_EMAIL_TO, attributesMap, "To"); + appendAttributeString(sb, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME_SENT, attributesMap, "On"); + } + return sb.toString(); + } + + private void appendAttributeString(StringBuilder sb, BlackboardAttribute.ATTRIBUTE_TYPE attribType, + Map attributesMap, String prependStr) { + + BlackboardAttribute attribute = attributesMap.get(attribType); + if (attribute != null) { + String attrVal = attribute.getDisplayString(); + if (!StringUtils.isEmpty(attrVal)) { + if (!StringUtils.isEmpty(prependStr)) { + sb.append(prependStr).append(" "); + } + sb.append(StringUtils.abbreviate(attrVal, 200)).append(" "); + } + } + } + + private String getAttribNameValue(BlackboardAttribute.ATTRIBUTE_TYPE attribType, Map attributesMap) { + BlackboardAttribute attribute = attributesMap.get(attribType); + if (attribute != null) { + return String.format("%s : %s", attribType.getDisplayName(), attribute.getDisplayString()); + } + return null; + } + + private Map getAttributesMap(BlackboardArtifact artifact) throws TskCoreException { + Map attributeMap = new HashMap<>(); + + List attributeList = artifact.getAttributes(); + for (BlackboardAttribute attribute : attributeList) { + BlackboardAttribute.ATTRIBUTE_TYPE type = BlackboardAttribute.ATTRIBUTE_TYPE.fromID(attribute.getAttributeType().getTypeID()); + attributeMap.put(type, attribute); + } + + return attributeMap; + } + + + // Variables declaration - do not modify//GEN-BEGIN:variables + private javax.swing.JLabel jLabel1; + private javax.swing.JButton jSourceGoToResultButton; + private javax.swing.JLabel jSourceNameLabel; + private javax.swing.JLabel jSourceTextLabel; + // End of variables declaration//GEN-END:variables +} diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/Metadata.java b/Core/src/org/sleuthkit/autopsy/contentviewers/Metadata.java index 126299f120..5f6c3eac9b 100644 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/Metadata.java +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/Metadata.java @@ -191,12 +191,21 @@ public class Metadata extends javax.swing.JPanel implements DataContentViewer { } try { - List sourceArtifacts = file.getArtifacts(ARTIFACT_TYPE.TSK_DOWNLOAD_SOURCE); - if (!sourceArtifacts.isEmpty()) { - BlackboardArtifact artifact = sourceArtifacts.get(0); - BlackboardAttribute urlAttr = artifact.getAttribute(new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_URL)); - if (urlAttr != null) { - addRow(sb, NbBundle.getMessage(this.getClass(), "Metadata.tableRowTitle.downloadSource"), urlAttr.getValueString()); + List associatedObjectArtifacts = file.getArtifacts(ARTIFACT_TYPE.TSK_ASSOCIATED_OBJECT); + if (!associatedObjectArtifacts.isEmpty()) { + BlackboardArtifact artifact = associatedObjectArtifacts.get(0); + BlackboardAttribute associatedArtifactAttribute = artifact.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ASSOCIATED_ARTIFACT)); + if (associatedArtifactAttribute != null) { + long artifactId = associatedArtifactAttribute.getValueLong(); + BlackboardArtifact associatedArtifact = artifact.getSleuthkitCase().getBlackboardArtifact(artifactId); + if (associatedArtifact != null && + ((associatedArtifact.getArtifactTypeID() == ARTIFACT_TYPE.TSK_WEB_DOWNLOAD.getTypeID()) || + (associatedArtifact.getArtifactTypeID() == ARTIFACT_TYPE.TSK_WEB_CACHE.getTypeID())) ) { + BlackboardAttribute urlAttr = associatedArtifact.getAttribute(new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_URL)); + if (urlAttr != null) { + addRow(sb, NbBundle.getMessage(this.getClass(), "Metadata.tableRowTitle.downloadSource"), urlAttr.getValueString()); + } + } } } } catch (TskCoreException ex) { diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/ExtractedContent.java b/Core/src/org/sleuthkit/autopsy/datamodel/ExtractedContent.java index e52e50c31c..ada8d91b36 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/ExtractedContent.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/ExtractedContent.java @@ -238,8 +238,8 @@ public class ExtractedContent implements AutopsyVisitableItem { doNotShow.add(new BlackboardArtifact.Type(TSK_INTERESTING_ARTIFACT_HIT)); doNotShow.add(new BlackboardArtifact.Type(TSK_ACCOUNT)); doNotShow.add(new BlackboardArtifact.Type(TSK_DATA_SOURCE_USAGE)); - doNotShow.add(new BlackboardArtifact.Type(TSK_DOWNLOAD_SOURCE)); - doNotShow.add(new BlackboardArtifact.Type(TSK_ASSOCIATED_OBJECT)); + //doNotShow.add(new BlackboardArtifact.Type(TSK_DOWNLOAD_SOURCE)); + //doNotShow.add(new BlackboardArtifact.Type(TSK_ASSOCIATED_OBJECT)); } private final PropertyChangeListener pcl = (PropertyChangeEvent evt) -> { diff --git a/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/Chrome.java b/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/Chrome.java index f75132c610..49ac9911fe 100644 --- a/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/Chrome.java +++ b/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/Chrome.java @@ -554,22 +554,24 @@ class Chrome extends Extract { RecentActivityExtracterModuleFactory.getModuleName(), NbBundle.getMessage(this.getClass(), "Chrome.moduleName"))); - BlackboardArtifact bbart = createArtifactWithAttributes(ARTIFACT_TYPE.TSK_WEB_DOWNLOAD, downloadFile, bbattributes); - if (bbart != null) { - bbartifacts.add(bbart); - } - - // find the downloaded file and create a TSK_DOWNLOAD_SOURCE for it.. - try { - for (AbstractFile downloadedFile : fileManager.findFiles(dataSource, FilenameUtils.getName(fullPath), FilenameUtils.getPath(fullPath))) { - BlackboardArtifact downloadSourceArt = downloadedFile.newArtifact(BlackboardArtifact.ARTIFACT_TYPE.TSK_DOWNLOAD_SOURCE); - downloadSourceArt.addAttributes(createDownloadSourceAttributes(result.get("url").toString())); - - bbartifacts.add(downloadSourceArt); - break; + BlackboardArtifact webDownloadArtifact = createArtifactWithAttributes(ARTIFACT_TYPE.TSK_WEB_DOWNLOAD, downloadFile, bbattributes); + if (webDownloadArtifact != null) { + bbartifacts.add(webDownloadArtifact); + + // find the downloaded file and create a TSK_ASSOCIATED_OBJECT for it, associating it with the TSK_WEB_DOWNLOAD artifact. + try { + for (AbstractFile downloadedFile : fileManager.findFiles(dataSource, FilenameUtils.getName(fullPath), FilenameUtils.getPath(fullPath))) { + BlackboardArtifact associatedObjectArtifact = downloadedFile.newArtifact(BlackboardArtifact.ARTIFACT_TYPE.TSK_ASSOCIATED_OBJECT); + associatedObjectArtifact.addAttribute( + new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ASSOCIATED_ARTIFACT, + RecentActivityExtracterModuleFactory.getModuleName(), webDownloadArtifact.getArtifactID())); + + bbartifacts.add(associatedObjectArtifact); + break; + } + } catch (TskCoreException ex) { + logger.log(Level.SEVERE, String.format("Error creating associated object artifact for file '%s'", fullPath), ex); //NON-NLS } - } catch (TskCoreException ex) { - logger.log(Level.SEVERE, String.format("Error creating download source artifact for file '%s'", fullPath), ex); //NON-NLS } } diff --git a/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/ChromeCacheExtractor.java b/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/ChromeCacheExtractor.java index efaf8934b2..4e1b5c3931 100644 --- a/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/ChromeCacheExtractor.java +++ b/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/ChromeCacheExtractor.java @@ -380,12 +380,12 @@ final class ChromeCacheExtractor { * Extracts the files if needed and adds as derived files, creates artifacts * * @param cacheEntryAddress cache entry address - * @param sourceArtifacts any source artifacts created are added to this collection + * @param associatedObjectArtifacts any associated object artifacts created are added to this collection * @param webCacheArtifacts any web cache artifacts created are added to this collection * * @return Optional derived file, is a derived file is added for the given entry */ - private List processCacheEntry(CacheAddress cacheEntryAddress, Collection sourceArtifacts, Collection webCacheArtifacts ) throws TskCoreException, IngestModuleException { + private List processCacheEntry(CacheAddress cacheEntryAddress, Collection associatedObjectArtifacts, Collection webCacheArtifacts ) throws TskCoreException, IngestModuleException { List derivedFiles = new ArrayList<>(); @@ -437,10 +437,6 @@ final class ChromeCacheExtractor { moduleName, cacheEntry.getHTTPHeaders()); - Collection sourceArtifactAttributes = new ArrayList<>(); - sourceArtifactAttributes.add(urlAttr); - sourceArtifactAttributes.add(createTimeAttr); - Collection webCacheAttributes = new ArrayList<>(); webCacheAttributes.add(urlAttr); webCacheAttributes.add(createTimeAttr); @@ -450,12 +446,7 @@ final class ChromeCacheExtractor { // add artifacts to the f_XXX file if (dataSegment.isInExternalFile() ) { try { - BlackboardArtifact sourceArtifact = cachedFileAbstractFile.get().newArtifact(ARTIFACT_TYPE.TSK_DOWNLOAD_SOURCE); - if (sourceArtifact != null) { - sourceArtifact.addAttributes(sourceArtifactAttributes); - sourceArtifacts.add(sourceArtifact); - } - + BlackboardArtifact webCacheArtifact = cacheEntryFile.get().getAbstractFile().newArtifact(ARTIFACT_TYPE.TSK_WEB_CACHE); if (webCacheArtifact != null) { webCacheArtifact.addAttributes(webCacheAttributes); @@ -469,6 +460,14 @@ final class ChromeCacheExtractor { moduleName, cachedFileAbstractFile.get().getId())); webCacheArtifacts.add(webCacheArtifact); + + BlackboardArtifact associatedObjectArtifact = cachedFileAbstractFile.get().newArtifact(ARTIFACT_TYPE.TSK_ASSOCIATED_OBJECT); + if (associatedObjectArtifact != null) { + associatedObjectArtifact.addAttribute( + new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ASSOCIATED_ARTIFACT, + moduleName, webCacheArtifact.getArtifactID())); + associatedObjectArtifacts.add(associatedObjectArtifact); + } } if (isBrotliCompressed) { @@ -497,12 +496,7 @@ final class ChromeCacheExtractor { "", TskData.EncodingType.NONE); - BlackboardArtifact sourceArtifact = derivedFile.newArtifact(ARTIFACT_TYPE.TSK_DOWNLOAD_SOURCE); - if (sourceArtifact != null) { - sourceArtifact.addAttributes(sourceArtifactAttributes); - sourceArtifacts.add(sourceArtifact); - } - + BlackboardArtifact webCacheArtifact = cacheEntryFile.get().getAbstractFile().newArtifact(ARTIFACT_TYPE.TSK_WEB_CACHE); if (webCacheArtifact != null) { webCacheArtifact.addAttributes(webCacheAttributes); @@ -516,6 +510,14 @@ final class ChromeCacheExtractor { moduleName, derivedFile.getId())); webCacheArtifacts.add(webCacheArtifact); + + BlackboardArtifact associatedObjectArtifact = derivedFile.newArtifact(ARTIFACT_TYPE.TSK_ASSOCIATED_OBJECT); + if (associatedObjectArtifact != null) { + associatedObjectArtifact.addAttribute( + new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ASSOCIATED_ARTIFACT, + moduleName, webCacheArtifact.getArtifactID())); + associatedObjectArtifacts.add(associatedObjectArtifact); + } } if (isBrotliCompressed) { diff --git a/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/ExtractSafari.java b/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/ExtractSafari.java index 704826047f..c11e4fde22 100755 --- a/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/ExtractSafari.java +++ b/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/ExtractSafari.java @@ -50,6 +50,7 @@ import org.sleuthkit.autopsy.ingest.ModuleDataEvent; import org.sleuthkit.autopsy.recentactivity.BinaryCookieReader.Cookie; import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.BlackboardArtifact; +import org.sleuthkit.datamodel.BlackboardAttribute; import org.sleuthkit.datamodel.Content; import org.sleuthkit.datamodel.TskCoreException; import org.xml.sax.SAXException; @@ -637,15 +638,17 @@ final class ExtractSafari extends Extract { time = date.getDate().getTime(); } - BlackboardArtifact bbart = origFile.newArtifact(BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_DOWNLOAD); - bbart.addAttributes(this.createDownloadAttributes(path, pathID, url, time, NetworkUtils.extractDomain(url), getName())); - bbartifacts.add(bbart); + BlackboardArtifact webDownloadArtifact = origFile.newArtifact(BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_DOWNLOAD); + webDownloadArtifact.addAttributes(this.createDownloadAttributes(path, pathID, url, time, NetworkUtils.extractDomain(url), getName())); + bbartifacts.add(webDownloadArtifact); - // find the downloaded file and create a TSK_DOWNLOAD_SOURCE for it. + // find the downloaded file and create a TSK_ASSOCIATED_OBJECT for it, associating it with the TSK_WEB_DOWNLOAD artifact. for (AbstractFile downloadedFile : fileManager.findFiles(dataSource, FilenameUtils.getName(path), FilenameUtils.getPath(path))) { - BlackboardArtifact downloadSourceArt = downloadedFile.newArtifact(BlackboardArtifact.ARTIFACT_TYPE.TSK_DOWNLOAD_SOURCE); - downloadSourceArt.addAttributes(createDownloadSourceAttributes(url)); - bbartifacts.add(downloadSourceArt); + BlackboardArtifact associatedObjectArtifact = downloadedFile.newArtifact(BlackboardArtifact.ARTIFACT_TYPE.TSK_ASSOCIATED_OBJECT); + associatedObjectArtifact.addAttribute( + new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ASSOCIATED_ARTIFACT, + RecentActivityExtracterModuleFactory.getModuleName(), webDownloadArtifact.getArtifactID())); + bbartifacts.add(associatedObjectArtifact); break; } diff --git a/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/ExtractZoneIdentifier.java b/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/ExtractZoneIdentifier.java index 250c55fa6e..51e3a8eff9 100755 --- a/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/ExtractZoneIdentifier.java +++ b/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/ExtractZoneIdentifier.java @@ -36,9 +36,11 @@ import org.sleuthkit.autopsy.ingest.DataSourceIngestModuleProgress; import org.sleuthkit.autopsy.ingest.IngestJobContext; import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.BlackboardArtifact; +import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_ASSOCIATED_OBJECT; import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_DOWNLOAD_SOURCE; import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_DOWNLOAD; import org.sleuthkit.datamodel.BlackboardAttribute; +import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ASSOCIATED_ARTIFACT; import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DOMAIN; import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_LOCATION; import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PATH_ID; @@ -94,7 +96,7 @@ final class ExtractZoneIdentifier extends Extract { return; } - Collection sourceArtifacts = new ArrayList<>(); + Collection associatedObjectArtifacts = new ArrayList<>(); Collection downloadArtifacts = new ArrayList<>(); for (AbstractFile zoneFile : zoneFiles) { @@ -104,7 +106,7 @@ final class ExtractZoneIdentifier extends Extract { } try { - processZoneFile(context, dataSource, zoneFile, sourceArtifacts, downloadArtifacts, knownPathIDs); + processZoneFile(context, dataSource, zoneFile, associatedObjectArtifacts, downloadArtifacts, knownPathIDs); } catch (TskCoreException ex) { addErrorMessage(Bundle.ExtractZone_process_errMsg()); String message = String.format("Failed to process zone identifier file %s", zoneFile.getName()); //NON-NLS @@ -112,23 +114,23 @@ final class ExtractZoneIdentifier extends Extract { } } - postArtifacts(sourceArtifacts); + postArtifacts(associatedObjectArtifacts); postArtifacts(downloadArtifacts); } /** * Process a single Zone Identifier file. * - * @param context IngetJobContext - * @param dataSource Content - * @param zoneFile Zone Indentifier file - * @param sourceArtifacts List for TSK_DOWNLOAD_SOURCE artifacts - * @param downloadArtifacts List for TSK_WEB_DOWNLOAD aritfacts - * + * @param context IngetJobContext + * @param dataSource Content + * @param zoneFile Zone Indentifier file + * @param associatedObjectArtifacts List for TSK_ASSOCIATED_OBJECT artifacts + * @param downloadArtifacts List for TSK_WEB_DOWNLOAD artifacts + * * @throws TskCoreException */ private void processZoneFile(IngestJobContext context, Content dataSource, - AbstractFile zoneFile, Collection sourceArtifacts, + AbstractFile zoneFile, Collection associatedObjectArtifacts, Collection downloadArtifacts, Set knownPathIDs) throws TskCoreException { @@ -155,16 +157,16 @@ final class ExtractZoneIdentifier extends Extract { BlackboardArtifact downloadBba = createDownloadArtifact(zoneFile, zoneInfo); if (downloadBba != null) { downloadArtifacts.add(downloadBba); + // create a TSK_ASSOCIATED_OBJECT for the downloaded file, associating it with the TSK_WEB_DOWNLOAD artifact. + if (downloadFile.getArtifactsCount(TSK_ASSOCIATED_OBJECT) == 0) { + BlackboardArtifact associatedObjectBba = createAssociatedObjectArtifact(downloadFile, downloadBba); + if (associatedObjectBba != null) { + associatedObjectArtifacts.add(associatedObjectBba); + } + } } } - // check if download has a child TSK_DOWNLOAD_SOURCE artifact, if not create one - if (downloadFile.getArtifactsCount(TSK_DOWNLOAD_SOURCE) == 0) { - BlackboardArtifact sourceBba = createDownloadSourceArtifact(downloadFile, zoneInfo); - if (sourceBba != null) { - sourceArtifacts.add(sourceBba); - } - } } } @@ -203,33 +205,26 @@ final class ExtractZoneIdentifier extends Extract { } /** - * Create a Download Source Artifact for the given ZoneIdentifierInfo + * Create a Associated Object Artifact for the given ZoneIdentifierInfo * object. * * @param downloadFile AbstractFile representing the file downloaded, not - * the zone identifier file. - * @param zoneInfo Zone identifier file wrapper object + * the zone identifier file. + * @param downloadBba TSK_WEB_DOWNLOAD artifact to associate with. * - * @return TSK_DOWNLOAD_SOURCE object for given parameters + * @return TSK_ASSOCIATED_OBJECT artifact. */ - private BlackboardArtifact createDownloadSourceArtifact(AbstractFile downloadFile, ZoneIdentifierInfo zoneInfo) { + private BlackboardArtifact createAssociatedObjectArtifact(AbstractFile downloadFile, BlackboardArtifact downloadBba) { Collection bbattributes = new ArrayList<>(); bbattributes.addAll(Arrays.asList( - new BlackboardAttribute(TSK_URL, - RecentActivityExtracterModuleFactory.getModuleName(), - StringUtils.defaultString(zoneInfo.getURL(), "")), - - new BlackboardAttribute(TSK_DOMAIN, - RecentActivityExtracterModuleFactory.getModuleName(), - (zoneInfo.getURL() != null) ? NetworkUtils.extractDomain(zoneInfo.getURL()) : ""), - - new BlackboardAttribute(TSK_LOCATION, - RecentActivityExtracterModuleFactory.getModuleName(), - StringUtils.defaultString(zoneInfo.getZoneIdAsString(), "")))); //NON-NLS + new BlackboardAttribute(TSK_ASSOCIATED_ARTIFACT, + RecentActivityExtracterModuleFactory.getModuleName(), + downloadBba.getArtifactID()) + )); - return createArtifactWithAttributes(TSK_DOWNLOAD_SOURCE, downloadFile, bbattributes); + return createArtifactWithAttributes(TSK_ASSOCIATED_OBJECT, downloadFile, bbattributes); } /** diff --git a/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/Firefox.java b/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/Firefox.java index dd4e70ee06..7fddeb0aa8 100644 --- a/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/Firefox.java +++ b/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/Firefox.java @@ -544,22 +544,25 @@ class Firefox extends Extract { domain)); //NON-NLS } - BlackboardArtifact bbart = createArtifactWithAttributes(ARTIFACT_TYPE.TSK_WEB_DOWNLOAD, downloadsFile, bbattributes); - if (bbart != null) { - bbartifacts.add(bbart); - } - - // find the downloaded file and create a TSK_DOWNLOAD_SOURCE for it. - try { - for (AbstractFile downloadedFile : fileManager.findFiles(dataSource, FilenameUtils.getName(downloadedFilePath), FilenameUtils.getPath(downloadedFilePath))) { - BlackboardArtifact downloadSourceArt = downloadedFile.newArtifact(BlackboardArtifact.ARTIFACT_TYPE.TSK_DOWNLOAD_SOURCE); - downloadSourceArt.addAttributes(createDownloadSourceAttributes(source)); - bbartifacts.add(downloadSourceArt); - break; + BlackboardArtifact webDownloadArtifact = createArtifactWithAttributes(ARTIFACT_TYPE.TSK_WEB_DOWNLOAD, downloadsFile, bbattributes); + if (webDownloadArtifact != null) { + bbartifacts.add(webDownloadArtifact); + + // find the downloaded file and create a TSK_ASSOCIATED_OBJECT for it, associating it with the TSK_WEB_DOWNLOAD artifact. + try { + for (AbstractFile downloadedFile : fileManager.findFiles(dataSource, FilenameUtils.getName(downloadedFilePath), FilenameUtils.getPath(downloadedFilePath))) { + BlackboardArtifact associatedObjectArtifact = downloadedFile.newArtifact(BlackboardArtifact.ARTIFACT_TYPE.TSK_ASSOCIATED_OBJECT); + associatedObjectArtifact.addAttribute( + new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ASSOCIATED_ARTIFACT, + RecentActivityExtracterModuleFactory.getModuleName(), webDownloadArtifact.getArtifactID())); + + bbartifacts.add(associatedObjectArtifact); + break; + } + } catch (TskCoreException ex) { + logger.log(Level.SEVERE, String.format("Error creating associated object artifact for file '%s'", + downloadedFilePath), ex); //NON-NLS } - } catch (TskCoreException ex) { - logger.log(Level.SEVERE, String.format("Error creating download source artifact for file '%s'", - downloadedFilePath), ex); //NON-NLS } } if (errors > 0) { @@ -681,22 +684,24 @@ class Firefox extends Extract { RecentActivityExtracterModuleFactory.getModuleName(), domain)); //NON-NLS } - BlackboardArtifact bbart = createArtifactWithAttributes(ARTIFACT_TYPE.TSK_WEB_DOWNLOAD, downloadsFile, bbattributes); - if (bbart != null) { - bbartifacts.add(bbart); - } + BlackboardArtifact webDownloadArtifact = createArtifactWithAttributes(ARTIFACT_TYPE.TSK_WEB_DOWNLOAD, downloadsFile, bbattributes); + if (webDownloadArtifact != null) { + bbartifacts.add(webDownloadArtifact); - // find the downloaded file and create a TSK_DOWNLOAD_SOURCE for it. - try { - for (AbstractFile downloadedFile : fileManager.findFiles(dataSource, FilenameUtils.getName(downloadedFilePath), FilenameUtils.getPath(downloadedFilePath))) { - BlackboardArtifact downloadSourceArt = downloadedFile.newArtifact(BlackboardArtifact.ARTIFACT_TYPE.TSK_DOWNLOAD_SOURCE); - downloadSourceArt.addAttributes(createDownloadSourceAttributes(url)); - bbartifacts.add(downloadSourceArt); - break; + // find the downloaded file and create a TSK_ASSOCIATED_OBJECT for it, associating it with the TSK_WEB_DOWNLOAD artifact. + try { + for (AbstractFile downloadedFile : fileManager.findFiles(dataSource, FilenameUtils.getName(downloadedFilePath), FilenameUtils.getPath(downloadedFilePath))) { + BlackboardArtifact associatedObjectArtifact = downloadedFile.newArtifact(BlackboardArtifact.ARTIFACT_TYPE.TSK_ASSOCIATED_OBJECT); + associatedObjectArtifact.addAttribute( + new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ASSOCIATED_ARTIFACT, + RecentActivityExtracterModuleFactory.getModuleName(), webDownloadArtifact.getArtifactID())); + bbartifacts.add(associatedObjectArtifact); + break; + } + } catch (TskCoreException ex) { + logger.log(Level.SEVERE, String.format("Error creating associated object artifact for file '%s'", + downloadedFilePath), ex); //NON-NLS } - } catch (TskCoreException ex) { - logger.log(Level.SEVERE, String.format("Error creating download source artifact for file '%s'", - downloadedFilePath), ex); //NON-NLS } } if (errors > 0) {