19 package com.basistech.df.cybertriage.autopsy.malwarescan;
 
   21 import com.google.common.net.InetAddresses;
 
   22 import java.net.InetAddress;
 
   23 import java.util.Collections;
 
   24 import java.util.HashSet;
 
   25 import java.util.List;
 
   26 import java.util.Locale;
 
   28 import java.util.logging.Level;
 
   29 import java.util.regex.Matcher;
 
   30 import java.util.regex.Pattern;
 
   31 import java.util.stream.Collectors;
 
   32 import org.apache.commons.lang3.StringUtils;
 
   40 class PathNormalizer {
 
   42     private static final Logger LOGGER = Logger.getLogger(PathNormalizer.class.getName());
 
   44     private static final String ANONYMIZED_USERNAME = 
"<user>";
 
   45     private static final String ANONYMIZED_IP = 
"<private_ip>";
 
   46     private static final String ANONYMIZED_HOSTNAME = 
"<hostname>";
 
   47     private static final String FORWARD_SLASH = 
"/";
 
   48     private static final String BACK_SLASH = 
"\\";
 
   50     private static final Pattern USER_PATH_FORWARD_SLASH_REGEX = Pattern.compile(
"(?<!all )([/]{0,1}\\Qusers\\E/)(?!(public|Default|defaultAccount|All Users))([^/]+)(/){0,1}", Pattern.CASE_INSENSITIVE);
 
   51     private static final Pattern USER_PATH_BACK_SLASH_REGEX = Pattern.compile(
"(?<!all )([\\\\]{0,1}\\Qusers\\E\\\\)(?!(public|Default|defaultAccount|All Users))([^\\\\]+)([\\\\]){0,1}", Pattern.CASE_INSENSITIVE);
 
   53     private static final Pattern USER_PATH_FORWARD_SLASH_REGEX_XP = Pattern.compile(
"([/]{0,1}\\Qdocuments and settings\\E/)(?!(Default User|All Users))([^/]+)(/){0,1}", Pattern.CASE_INSENSITIVE);
 
   54     private static final Pattern USER_PATH_BACK_SLASH_REGEX_XP = Pattern.compile(
"([\\\\]{0,1}\\Qdocuments and settings\\E\\\\)(?!(Default User|All Users))([^\\\\]+)(\\\\){0,1}", Pattern.CASE_INSENSITIVE);
 
   56     private static final Pattern UNC_PATH_FORWARD_SLASH_PATTERN = Pattern.compile(
"(//)([^/]+)(/){0,1}");
 
   57     private static final Pattern UNC_PATH_BACK_SLASH_PATTERN = Pattern.compile(
"(\\\\\\\\)([^\\\\]+)(\\\\){0,1}");
 
   59     private static final String USERNAME_REGEX_REPLACEMENT = 
"$1" + ANONYMIZED_USERNAME + 
"$4";
 
   61     private final SleuthkitCase skCase;
 
   63     PathNormalizer(SleuthkitCase skCase) {
 
   67     protected List<String> getUsernames() {
 
   69             return this.skCase.getOsAccountManager().getOsAccounts().stream()
 
   70                     .filter(acct -> acct != null)
 
   71                     .map(acct -> acct.getLoginName().orElse(null))
 
   72                     .filter(StringUtils::isNotBlank)
 
   73                     .collect(Collectors.toList());
 
   74         } 
catch (TskCoreException ex) {
 
   75             LOGGER.log(Level.WARNING, 
"There was an error getting current os accounts", ex);
 
   76             return Collections.emptyList();
 
   80     public String normalizePath(String inputString) {
 
   81         if (StringUtils.isBlank(inputString)) {
 
   85         String anonymousString = anonymizeUserFromPathsWithForwardSlashes(inputString);
 
   86         anonymousString = anonymizeUserFromPathsWithBackSlashes(anonymousString);
 
   87         anonymousString = anonymizeServerFromUNCPath(anonymousString);
 
   89         return anonymousString;
 
   92     private String anonymizeUserFromPathsWithForwardSlashes(String stringWithUsername) {
 
   93         String anonymousString = stringWithUsername;
 
   94         anonymousString = regexReplace(anonymousString, USER_PATH_FORWARD_SLASH_REGEX_XP, USERNAME_REGEX_REPLACEMENT);
 
   95         anonymousString = regexReplace(anonymousString, USER_PATH_FORWARD_SLASH_REGEX, USERNAME_REGEX_REPLACEMENT);
 
   96         anonymousString = replaceFolder(anonymousString, getUsernames(), ANONYMIZED_USERNAME, FORWARD_SLASH);
 
   97         return anonymousString;
 
  102     private String anonymizeUserFromPathsWithBackSlashes(String stringWithUsername) {
 
  103         String anonymousString = stringWithUsername;
 
  104         anonymousString = regexReplace(anonymousString, USER_PATH_BACK_SLASH_REGEX_XP, USERNAME_REGEX_REPLACEMENT);
 
  105         anonymousString = regexReplace(anonymousString, USER_PATH_BACK_SLASH_REGEX, USERNAME_REGEX_REPLACEMENT);
 
  106         anonymousString = replaceFolder(anonymousString, getUsernames(), ANONYMIZED_USERNAME, BACK_SLASH);
 
  108         return anonymousString;
 
  111     private String anonymizeServerFromUNCPath(String inputString) {
 
  113         Set<String> serverNames = 
new HashSet<>();
 
  114         String anonymousString = inputString.toLowerCase(Locale.ENGLISH);
 
  116         Matcher forwardSlashMatcher = UNC_PATH_FORWARD_SLASH_PATTERN.matcher(anonymousString);
 
  117         while (forwardSlashMatcher.find()) {
 
  118             String serverName = forwardSlashMatcher.group(2);
 
  119             serverNames.add(serverName);
 
  122         Matcher backSlashMatcher = UNC_PATH_BACK_SLASH_PATTERN.matcher(anonymousString);
 
  123         while (backSlashMatcher.find()) {
 
  124             String serverName = backSlashMatcher.group(2);
 
  125             serverNames.add(serverName);
 
  128         for (String serverName : serverNames) {
 
  130             if (StringUtils.isBlank(serverName)) {
 
  134             if (InetAddresses.isInetAddress(serverName) && isLocalIP(serverName)) {
 
  135                 anonymousString = replaceFolder(anonymousString, Collections.singletonList(serverName), ANONYMIZED_IP);
 
  137                 anonymousString = replaceFolder(anonymousString, Collections.singletonList(serverName), ANONYMIZED_HOSTNAME);
 
  142         return anonymousString;
 
  145     private static String regexReplace(String orig, Pattern pattern, String regexReplacement) {
 
  146         Matcher matcher = pattern.matcher(orig);
 
  147         return matcher.replaceAll(regexReplacement);
 
  150     private static String replaceFolder(String orig, List<String> valuesToReplace, String replacementValue) {
 
  151         String anonymized = orig;
 
  152         anonymized = replaceFolder(anonymized, valuesToReplace, replacementValue, FORWARD_SLASH);
 
  153         anonymized = replaceFolder(anonymized, valuesToReplace, replacementValue, BACK_SLASH);
 
  157     private static String replaceFolder(String orig, List<String> valuesToReplace, String replacementValue, String folderDelimiter) {
 
  158         if (orig == null || valuesToReplace == null) {
 
  162         String anonymousString = orig;
 
  165         folderDelimiter = StringUtils.defaultString(folderDelimiter);
 
  166         replacementValue = StringUtils.defaultString(replacementValue);
 
  169         for (String valueToReplace : valuesToReplace) {
 
  170             if (StringUtils.isNotEmpty(valueToReplace)) {
 
  171                 anonymousString = StringUtils.replace(anonymousString,
 
  172                         folderDelimiter + valueToReplace + folderDelimiter,
 
  173                         folderDelimiter + replacementValue + folderDelimiter);
 
  177         return anonymousString;
 
  190     public static boolean isLocalIP(String ipAddress) {
 
  192             InetAddress a = InetAddresses.forString(ipAddress);
 
  193             return a.isAnyLocalAddress() || a.isSiteLocalAddress()
 
  194                     || a.isLoopbackAddress() || a.isLinkLocalAddress();
 
  195         } 
catch (IllegalArgumentException ex) {
 
  196             LOGGER.log(Level.WARNING, 
"Invalid IP string", ex);