/* * Autopsy Forensic Browser * * Copyright 2013 Basis Technology Corp. * Contact: carrier <at> sleuthkit <dot> 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.modules.stix; import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.datamodel.SleuthkitCase; import org.sleuthkit.datamodel.BlackboardArtifact; import org.sleuthkit.datamodel.BlackboardAttribute; import org.sleuthkit.datamodel.TskCoreException; import java.util.List; import java.util.ArrayList; import org.mitre.cybox.common_2.AnyURIObjectPropertyType; import org.mitre.cybox.objects.URLHistory; import org.mitre.cybox.objects.URLHistoryEntryType; /** * */ class EvalURLHistoryObj extends EvaluatableObject { private final URLHistory obj; public EvalURLHistoryObj(URLHistory a_obj, String a_id, String a_spacing) { obj = a_obj; id = a_id; spacing = a_spacing; } @Override public synchronized ObservableResult evaluate() { setWarnings(""); if ((obj.getBrowserInformation() == null) && (obj.getURLHistoryEntries() == null)) { return new ObservableResult(id, "URLHistoryObject: No browser info or history entries found", //NON-NLS spacing, ObservableResult.ObservableState.INDETERMINATE, null); } // For displaying what we were looking for in the results String baseSearchString = ""; String finalResultsStr = ""; // The browser info is the same for each entry boolean haveBrowserName = false; if (obj.getBrowserInformation() != null) { if (obj.getBrowserInformation().getName() != null) { haveBrowserName = true; } baseSearchString = "Browser \"" + obj.getBrowserInformation().getName() + "\""; //NON-NLS } // Matching artifacts List<BlackboardArtifact> finalHits = new ArrayList<BlackboardArtifact>(); if (obj.getURLHistoryEntries() != null) { for (URLHistoryEntryType entry : obj.getURLHistoryEntries()) { boolean haveURL = false; boolean haveHostname = false; boolean haveReferrer = false; boolean havePageTitle = false; boolean haveUserProfile = false; setUnsupportedEntryFieldWarnings(entry); // At present, the search string doesn't get reported (because there could be different ones // for multiple URL History Entries) but it's good for debugging. String searchString = baseSearchString; if ((entry.getURL() != null) && (entry.getURL().getValue() != null)) { haveURL = true; if (!searchString.isEmpty()) { searchString += " and "; //NON-NLS } searchString += "URL \"" + entry.getURL().getValue().getValue() + "\""; //NON-NLS } if ((entry.getReferrerURL() != null) && (entry.getReferrerURL().getValue() != null)) { haveReferrer = true; if (!searchString.isEmpty()) { searchString += " and "; //NON-NLS } searchString += "Referrer \"" + entry.getReferrerURL().getValue().getValue() + "\""; //NON-NLS } if (entry.getUserProfileName() != null) { haveUserProfile = true; if (!searchString.isEmpty()) { searchString += " and "; //NON-NLS } searchString += "UserProfile \"" + entry.getUserProfileName().getValue() + "\""; //NON-NLS } if (entry.getPageTitle() != null) { havePageTitle = true; if (!searchString.isEmpty()) { searchString += " and "; //NON-NLS } searchString += "Page title \"" + entry.getPageTitle().getValue() + "\""; //NON-NLS } if ((entry.getHostname() != null) && (entry.getHostname().getHostnameValue() != null)) { haveHostname = true; if (!searchString.isEmpty()) { searchString += " and "; //NON-NLS } searchString += "Hostname \"" + entry.getHostname().getHostnameValue().getValue() + "\""; //NON-NLS } if (!finalResultsStr.isEmpty()) { finalResultsStr += ", "; } finalResultsStr += searchString; if (!(haveURL || haveHostname || haveReferrer || havePageTitle || haveUserProfile || haveBrowserName)) { return new ObservableResult(id, "URLHistoryObject: No evaluatable fields found", //NON-NLS spacing, ObservableResult.ObservableState.INDETERMINATE, null); } try { Case case1 = Case.getCurrentCase(); SleuthkitCase sleuthkitCase = case1.getSleuthkitCase(); List<BlackboardArtifact> artList = sleuthkitCase.getBlackboardArtifacts(BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_HISTORY); for (BlackboardArtifact art : artList) { boolean foundURLMatch = false; boolean foundHostnameMatch = false; boolean foundReferrerMatch = false; boolean foundPageTitleMatch = false; boolean foundUserProfileMatch = false; boolean foundBrowserNameMatch = false; for (BlackboardAttribute attr : art.getAttributes()) { if ((attr.getAttributeType().getTypeID() == BlackboardAttribute.ATTRIBUTE_TYPE.TSK_URL.getTypeID()) && (haveURL)) { if (entry.getURL().getValue() instanceof AnyURIObjectPropertyType) { foundURLMatch = compareStringObject(entry.getURL().getValue().getValue().toString(), entry.getURL().getValue().getCondition(), entry.getURL().getValue().getApplyCondition(), attr.getValueString()); } else { addWarning("Non-AnyURIObjectPropertyType found in URL value field"); //NON-NLS } } if ((attr.getAttributeType().getTypeID() == BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DOMAIN.getTypeID()) && (haveHostname)) { foundHostnameMatch = compareStringObject(entry.getHostname().getHostnameValue(), attr.getValueString()); } if ((attr.getAttributeType().getTypeID() == BlackboardAttribute.ATTRIBUTE_TYPE.TSK_REFERRER.getTypeID()) && (haveReferrer)) { if (entry.getReferrerURL().getValue() instanceof AnyURIObjectPropertyType) { foundReferrerMatch = compareStringObject(entry.getReferrerURL().getValue().getValue().toString(), entry.getURL().getValue().getCondition(), entry.getURL().getValue().getApplyCondition(), attr.getValueString()); } else { addWarning("Non-AnyURIObjectPropertyType found in URL value field"); //NON-NLS } } if ((attr.getAttributeType().getTypeID() == BlackboardAttribute.ATTRIBUTE_TYPE.TSK_TITLE.getTypeID()) && (havePageTitle)) { foundPageTitleMatch = compareStringObject(entry.getPageTitle(), attr.getValueString()); } if ((attr.getAttributeType().getTypeID() == BlackboardAttribute.ATTRIBUTE_TYPE.TSK_USER_NAME.getTypeID()) && (haveUserProfile)) { foundUserProfileMatch = compareStringObject(entry.getUserProfileName(), attr.getValueString()); } if ((attr.getAttributeType().getTypeID() == BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PROG_NAME.getTypeID()) && (haveBrowserName)) { foundBrowserNameMatch = compareStringObject(obj.getBrowserInformation().getName(), null, null, attr.getValueString()); } } if (((!haveURL) || foundURLMatch) && ((!haveHostname) || foundHostnameMatch) && ((!haveReferrer) || foundReferrerMatch) && ((!havePageTitle) || foundPageTitleMatch) && ((!haveUserProfile) || foundUserProfileMatch) && ((!haveBrowserName) || foundBrowserNameMatch)) { finalHits.add(art); } } } catch (TskCoreException ex) { return new ObservableResult(id, "URLHistoryObject: Exception during evaluation: " + ex.getLocalizedMessage(), //NON-NLS spacing, ObservableResult.ObservableState.INDETERMINATE, null); } } if (!finalHits.isEmpty()) { List<StixArtifactData> artData = new ArrayList<StixArtifactData>(); for (BlackboardArtifact a : finalHits) { artData.add(new StixArtifactData(a.getObjectID(), id, "URLHistory")); //NON-NLS } return new ObservableResult(id, "URLHistoryObject: Found at least one match for " + finalResultsStr, //NON-NLS spacing, ObservableResult.ObservableState.TRUE, artData); } // Didn't find any matches return new ObservableResult(id, "URLHistoryObject: No matches found for " + finalResultsStr, //NON-NLS spacing, ObservableResult.ObservableState.FALSE, null); } else if (haveBrowserName) { // It doesn't seem too useful, but we can just search for the browser name // if there aren't any URL entries try { Case case1 = Case.getCurrentCase(); SleuthkitCase sleuthkitCase = case1.getSleuthkitCase(); List<BlackboardArtifact> artList = sleuthkitCase.getBlackboardArtifacts(BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_HISTORY); for (BlackboardArtifact art : artList) { boolean foundBrowserNameMatch = false; for (BlackboardAttribute attr : art.getAttributes()) { if ((attr.getAttributeType().getTypeID() == BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PROG_NAME.getTypeID()) && (haveBrowserName)) { foundBrowserNameMatch = compareStringObject(obj.getBrowserInformation().getName(), null, null, attr.getValueString()); } } if (foundBrowserNameMatch) { finalHits.add(art); } } if (!finalHits.isEmpty()) { List<StixArtifactData> artData = new ArrayList<StixArtifactData>(); for (BlackboardArtifact a : finalHits) { artData.add(new StixArtifactData(a.getObjectID(), id, "URLHistory")); //NON-NLS } return new ObservableResult(id, "URLHistoryObject: Found at least one match", //NON-NLS spacing, ObservableResult.ObservableState.TRUE, artData); } // Didn't find any matches return new ObservableResult(id, "URLHistoryObject: No matches found for " + baseSearchString, //NON-NLS spacing, ObservableResult.ObservableState.FALSE, null); } catch (TskCoreException ex) { return new ObservableResult(id, "URLHistoryObject: Exception during evaluation: " + ex.getLocalizedMessage(), //NON-NLS spacing, ObservableResult.ObservableState.INDETERMINATE, null); } } else { // Nothing to search for return new ObservableResult(id, "URLHistoryObject: No evaluatable fields found", //NON-NLS spacing, ObservableResult.ObservableState.INDETERMINATE, null); } } /** * Set up the warning for any fields in the URL_History_Entry object that * aren't supported. */ private void setUnsupportedEntryFieldWarnings(URLHistoryEntryType entry) { List<String> fieldNames = new ArrayList<String>(); if (entry.getUserProfileName() != null) { fieldNames.add("User_Profile_Name"); //NON-NLS } if (entry.getVisitCount() != null) { fieldNames.add("Visit_Count"); //NON-NLS } if (entry.getManuallyEnteredCount() != null) { fieldNames.add("Manually_Entered_Count"); //NON-NLS } if (entry.getModificationDateTime() != null) { fieldNames.add("Modification_DateTime"); //NON-NLS } if (entry.getExpirationDateTime() != null) { fieldNames.add("Expiration_DateTime"); //NON-NLS } if (entry.getFirstVisitDateTime() != null) { fieldNames.add("First_Visit_DateTime"); //NON-NLS } if (entry.getLastVisitDateTime() != null) { fieldNames.add("Last_Visit_DateTime"); //NON-NLS } String warningStr = ""; for (String name : fieldNames) { if (!warningStr.isEmpty()) { warningStr += ", "; } warningStr += name; } addWarning("Unsupported URL_History_Entry field(s): " + warningStr); //NON-NLS } }