def __init__(self, host, args): super(FileHashCollector, self).__init__(host, args) if 'path' not in args: raise ArgumentException('FileHashCollector requires path argument') if 'type' not in args: raise ArgumentException('FileHashCollector requires type argument') if args['type'] not in FileHashCollector.HASH_COMMANDS.keys(): raise ArgumentException('Unknown hash type: ' + args['type'])
def __init__(self, host, args): super(ResolveFilepathCollector, self).__init__(host, args) if 'filepath' not in args: raise ArgumentException('ResolveFilepathCollector requires filepath argument') for i in ('value_datatypes', 'value_masks', 'value_operations'): if i not in args: raise ArgumentException('ResolveFilepathCollector requires ' + i + ' argument') if args['value_datatypes']['filepath'] != 'string': raise ArgumentException('ResolveFilepathCollector requires string filepath') # NOTE: operation should be already validated by EntityObjectType if args['value_operations']['filepath'] == 'pattern match' and args['behavior_recurse_file_system'] == 'defined': raise ArgumentException('ResolveFilepathCollector behavior_recurse_file_system set to defined with pattern match operation')
def __init__(self, host, args): super(ResolvePathFilenameCollector, self).__init__(host, args) if 'path' not in args: raise ArgumentException('ResolvePathFilenameCollector requires path argument') if 'filename' not in args: raise ArgumentException('ResolvePathFilenameCollector requires filename argument') for i in ('value_datatypes', 'value_masks', 'value_operations'): if i not in args: raise ArgumentException('ResolvePathFilenameCollector requires ' + i + ' argument') if args['value_datatypes']['path'] != 'string': raise ArgumentException('ResolvePathFilenameCollector requires string path') if args['value_datatypes']['filename'] != 'string': raise ArgumentException('ResolvePathFilenameCollector requires string filename') # NOTE: operation should be already validated by EntityObjectType # TODO the max_depth behavior MUST not be used when a pattern match is used with a path entity # TODO the recurse behavior MUST not be used when a pattern match is used with a path entity # TODO the recurse_direction behavior MUST not be used when a pattern match is used with a path entity # the recurse_file_system behavior MUST not be set to 'defined' when a pattern match is used with a path entity if args['value_operations']['path'] == 'pattern match' and args['behavior_recurse_file_system'] == 'defined': raise ArgumentException('ResolvePathFilenameCollector behavior_recurse_file_system set to defined with path pattern match operation')
def collect(self): if self.args['value_operations']['path'] in ['equals', 'case insensitive equals']: # check if path exists col = self.host.load_collector('DirectoryExistsCollector', {'path': self.args['path']}) if not col.collect(): raise FileNotFoundError(self.args['path'] + ' was not found') paths = [self.args['path']] elif self.args['value_operations']['path'] in ['not equal', 'case insensitive not equal']: raise NotImplementedError(self.args['value_operations']['path'] + ' operation not supported for ResolvePathFilenameCollector') elif self.args['value_operations']['path'] == 'pattern match': path = self.args['path'] logger.debug('Matching pattern ' + path) # strip off leading ^ or trailing $ as they are assumed if path.startswith('^'): path = path[1:] if path.endswith('$'): path = path[:-1] paths = [] m = re.match(r'^([a-zA-Z]):\\', path) if m: # C:\ local abs path drive = m.group(1) + ':\\' logger.debug('Absolute path on drive ' + drive) cmd = "Get-PSDrive -PSProvider FileSystem | % { $_.Root }" return_code, out_lines, err_lines = self.host.exec_command('powershell -Command "' + cmd.replace('\"', '\\"') + '"') if drive not in out_lines: # don't have the drive, so path won't match raise FileNotFoundError(self.args['path'] + ' was not found') start = m.group(1) + ':' fp = path.split('\\') fp = fp[1:] for p in fp: logger.debug('Checking if path component ' + p + ' exists') cmd = "Get-Item -LiteralPath '" + start + '\\' + p + "' -ErrorAction Ignore | % { $_.Name }" return_code, out_lines, err_lines = self.host.exec_command('powershell -Command "' + cmd.replace('\"', '\\"') + '"') if return_code == 0 and len(out_lines) == 1: logger.debug(p + ' exists') start = start + '\\' + p else: logger.debug(p + ' does not exist; using ' + start + ' as starting point') break logger.debug('Recursing from ' + start) cmd = "Get-ChildItem -LiteralPath '" + start + "' -Recurse -ErrorAction Ignore | % { $_.FullName }" return_code, out_lines, err_lines = self.host.exec_command('powershell -Command "' + cmd.replace('\"', '\\"') + '"') if return_code != 0 or len(out_lines) < 1: raise FileNotFoundError(self.args['path'] + ' was not found') for l in out_lines: m = re.fullmatch(self.args['path'], l) if m: logger.debug(l + ' matches ' + self.args['path']) paths.append(l) elif path.startswith(r'\\\\\?\\UNC\\'): # \\?\UNC\ extended UNC length path raise NotImplementedError('extended UNC paths are not yet supported') elif path.startswith(r'\\\\\?\\'): # \\?\ extended length path raise NotImplementedError('extended paths are not yet supported') elif path.startswith(r'\\\\\.\\'): # \\.\ device namespace path raise NotImplementedError('device paths are not yet supported') elif path.startswith(r'\\\\'): # \\server\share UNC path m = re.match(r'^\\\\([^\\]+)\\') if not m: raise ArgumentException('Invalid UNC path: ' + path) server = m.group(1) logger.debug('UNC path on server ' + server) start = '\\\\' + server fp = path.split('\\') fp = fp[3:] for p in fp: logger.debug('Checking if path component ' + p + ' exists') cmd = "Get-Item -LiteralPath '" + start + '\\' + p + "' -ErrorAction Ignore | % { $_.Name }" return_code, out_lines, err_lines = self.host.exec_command('powershell -Command "' + cmd.replace('\"', '\\"') + '"') if return_code == 0 and len(out_lines) == 1: logger.debug(p + ' exists') start = start + '\\' + p else: logger.debug(p + ' does not exist; using ' + start + ' as starting point') break logger.debug('Recursing from ' + start) cmd = "Get-ChildItem -LiteralPath '" + start + "' -Recurse -ErrorAction Ignore | % { $_.FullName }" return_code, out_lines, err_lines = self.host.exec_command('powershell -Command "' + cmd.replace('\"', '\\"') + '"') if return_code != 0 or len(out_lines) < 1: raise FileNotFoundError(self.args['path'] + ' was not found') for l in out_lines: m = re.fullmatch(self.args['path'], l) if m: logger.debug(l + ' matches ' + self.args['path']) paths.append(l) elif path.startswith(r'\.\.\\'): # ..\ relative parent path cmd = "(Get-Item -Path '..\\' -Verbose).FullName" return_code, out_lines, err_lines = self.host.exec_command('powershell -Command "' + cmd.replace('\"', '\\"') + '"') start = out_lines[0] logger.debug('Recursing from ' + start) cmd = "Get-ChildItem -LiteralPath '" + start + "' -Recurse -ErrorAction Ignore | % { $_.FullName }" return_code, out_lines, err_lines = self.host.exec_command('powershell -Command "' + cmd.replace('\"', '\\"') + '"') if return_code != 0 or len(out_lines) < 1: raise FileNotFoundError(self.args['path'] + ' was not found') for l in out_lines: m = re.fullmatch(self.args['path'], l.replace(start, '..')) if m: logger.debug(l + ' matches ' + self.args['path']) paths.append(l) elif path.startswith(r'\.\\'): # .\ relative current path cmd = "(Get-Item -Path '.\\' -Verbose).FullName" return_code, out_lines, err_lines = self.host.exec_command('powershell -Command "' + cmd.replace('\"', '\\"') + '"') start = out_lines[0] logger.debug('Recursing from ' + start) cmd = "Get-ChildItem -LiteralPath '" + start + "' -Recurse -ErrorAction Ignore | % { $_.FullName }" return_code, out_lines, err_lines = self.host.exec_command('powershell -Command "' + cmd.replace('\"', '\\"') + '"') if return_code != 0 or len(out_lines) < 1: raise FileNotFoundError(self.args['path'] + ' was not found') for l in out_lines: m = re.fullmatch(self.args['path'], l.replace(start, '.')) if m: logger.debug(l + ' matches ' + self.args['path']) paths.append(l) else: raise ArgumentException('Invalid path: ' + path) # TODO imp behavior_windows_view filepaths = [] for path in paths: if self.args['behavior_recurse_file_system'] == 'local' and path.startswith('\\\\'): continue if self.args['value_operations']['filename'] in ['equals', 'case insensitive equals']: filepaths.extend(self.search_path_for(path, self.args['filename'], '-eq', self.args['behavior_max_depth'], self.args['behavior_recurse_direction'])) elif self.args['value_operations']['filename'] in ['not equal', 'case insensitive not equal']: raise NotImplementedError(self.args['value_operations']['filename'] + ' operation not supported for ResolvePathFilenameCollector') elif self.args['value_operations']['filename'] == 'pattern match': filepaths.extend(self.search_path_for(path, self.args['filename'], '-match', self.args['behavior_max_depth'], self.args['behavior_recurse_direction'])) else: raise NotImplementedError('Unknown operation not supported for ResolvePathFilenameCollector filename') return filepaths
def collect(self): if self.args['value_operations']['path'] == 'equals': # check if path exists col = self.host.load_collector('DirectoryExistsCollector', {'path': self.args['path']}) if not col.collect(): raise FileNotFoundError(self.args['path'] + ' was not found') paths = [self.args['path']] elif self.args['value_operations']['path'] == 'not equal': raise NotImplementedError( 'not equal operation not supported for ResolvePathFilenameCollector' ) elif self.args['value_operations'][ 'path'] == 'case insensitive equals': # check if path exists col = self.host.load_collector('DirectoryExistsCollector', { 'path': self.args['path'], 'case_insensitive': True }) if not col.collect(): raise FileNotFoundError(self.args['path'] + ' was not found') paths = [self.args['path']] elif self.args['value_operations'][ 'path'] == 'case insensitive not equal': raise NotImplementedError( 'not equal operation not supported for ResolvePathFilenameCollector' ) elif self.args['value_operations']['path'] == 'pattern match': path = self.args['path'].replace('\"', '\\"') cmd = 'find -H / -type d 2>/dev/null | grep --perl-regexp --line-regexp --colour=never "' + path + '"' logger.debug(cmd) return_code, out_lines, err_lines = self.host.exec_command(cmd) if return_code != 0 or len(out_lines) < 1: raise FileNotFoundError('Unable to find pattern ' + self.args['path'] + '; using base dir ' + basedir + '; regex ' + regex) paths = [] for d in out_lines: col = self.host.load_collector('DirectoryExistsCollector', {'path': d}) if col.collect(): paths.append(d) else: raise NotImplementedError( 'Unknown operation not supported for ResolvePathFilenameCollector' ) opts = [] if self.args['behavior_recurse_direction'] == 'down': if self.args['behavior_max_depth'] == -1: pass elif self.args['behavior_max_depth'] >= 0: opts.append('-maxdepth ' + str(self.args['behavior_max_depth'])) else: raise ArgumentException( 'ResolvePathFilenameCollector arg behavior_max_depth is invalid ' + str(self.args['behavior_max_depth'])) if self.args['behavior_recurse_file_system'] == 'defined': opts.append('-xdev') elif self.args['behavior_recurse_file_system'] == 'local': logger.warn( 'Local/remote filesystem detection is not yet implemented') elif self.args['behavior_recurse_file_system'] == 'all': pass else: raise ArgumentException( 'ResolvePathFilenameCollector arg behavior_recurse_file_system is invalid ' + str(self.args['behavior_recurse_file_system'])) elif self.args['behavior_recurse_direction'] == 'none': pass elif self.args['behavior_recurse_direction'] == 'up': raise NotImplementedError( 'Upward recursion is not yet implemented') else: raise ArgumentException( 'ResolvePathFilenameCollector arg behavior_recurse_direction is invalid ' + str(self.args['behavior_recurse_direction'])) # NOTE: behavior_windows_view is ignored filepaths = [] filename = self.args['filename'].replace("'", "\\'") for path in paths: path = path.replace("'", "\\'") if self.args['value_operations']['filename'] == 'equals': if self.args['behavior_recurse'] == 'directories': # TODO might want to use -H cmd = 'find \'' + path + '\' ' + ' '.join( opts) + ' -name \'' + filename + '\'' elif self.args['behavior_recurse'] in ( 'symlinks', 'symlinks and directories'): cmd = 'find -L \'' + path + '\' ' + ' '.join( opts) + ' -name \'' + filename + '\'' else: raise ArgumentException( 'ResolvePathFilenameCollector arg behavior_recurse is invalid ' + str(self.args['behavior_recurse'])) return_code, out_lines, err_lines = self.host.exec_command(cmd) if return_code != 0: raise FileNotFoundError('Unable to find ' + filename + ' in ' + path) filepaths.extend(out_lines) elif self.args['value_operations']['filename'] == 'not equal': raise NotImplementedError( 'not equal operation not supported for ResolvePathFilenameCollector' ) elif self.args['value_operations'][ 'filename'] == 'case insensitive equals': if self.args['behavior_recurse'] == 'directories': # TODO might want to use -H cmd = 'find \'' + path + '\' ' + ' '.join( opts) + ' -iname \'' + filename + '\'' elif self.args['behavior_recurse'] in ( 'symlinks', 'symlinks and directories'): cmd = 'find -L \'' + path + '\' ' + ' '.join( opts) + ' -iname \'' + filename + '\'' else: raise ArgumentException( 'ResolvePathFilenameCollector arg behavior_recurse is invalid ' + str(self.args['behavior_recurse'])) return_code, out_lines, err_lines = self.host.exec_command(cmd) if return_code != 0: raise FileNotFoundError('Unable to find ' + filename + ' in ' + path) filepaths.extend(out_lines) elif self.args['value_operations'][ 'filename'] == 'case insensitive not equal': raise NotImplementedError( 'not equal operation not supported for ResolvePathFilenameCollector' ) elif self.args['value_operations']['filename'] == 'pattern match': if self.args['behavior_recurse'] == 'directories': # TODO might want to use -H cmd = 'find \'' + path + '\' ' + ' '.join( opts) + ' -regex \'' + filename + '\'' elif self.args['behavior_recurse'] in ( 'symlinks', 'symlinks and directories'): cmd = 'find -L \'' + path + '\' ' + ' '.join( opts) + ' -regex \'' + filename + '\'' else: raise ArgumentException( 'ResolvePathFilenameCollector arg behavior_recurse is invalid ' + str(self.args['behavior_recurse'])) return_code, out_lines, err_lines = self.host.exec_command(cmd) if return_code != 0: raise FileNotFoundError('Unable to find ' + filename + ' in ' + path) filepaths.extend(out_lines) else: raise NotImplementedError( 'Unknown operation not supported for ResolvePathFilenameCollector filename' ) return filepaths
def __init__(self, host, args): super(EnvironmentVariableCollector, self).__init__(host, args) if 'name' not in args: raise ArgumentException('EnvironmentVariableCollector requires name argument')
def __init__(self, host, args): super(DirectoryContentsCollector, self).__init__(host, args) if 'path' not in args: raise ArgumentException( 'DirectoryContentsCollector requires path argument')