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);