def osquery( self, query: Text, timeout: int = 30000, ignore_stderr_errors: bool = False) -> osquery_pb2.OsqueryTable: """Runs given query on the client. Args: query: An SQL query to run against osquery on the client. timeout: Query timeout in millis. ignore_stderr_errors: If true, will not break in case of stderr errors. Returns: An osquery table corresponding to the result of running the query. """ args = osquery_pb2.OsqueryFlowArgs() args.query = query args.timeout_millis = timeout args.ignore_stderr_errors = ignore_stderr_errors try: oq = self._client.CreateFlow(name='OsqueryFlow', args=args) except api_errors.AccessForbiddenError as e: raise errors.ApprovalMissingError(self.id, e) _timeout.await_flow(oq) result = list(oq.ListResults())[0].payload if not isinstance(result, osquery_pb2.OsqueryResult): raise TypeError(f'Unexpected flow result type: {type(result)}') return result.table
def collect( self, artifact: Text, ) -> Sequence[Union[message.Message, api_utils.UnknownProtobuf]]: """Collects specified artifact. Args: artifact: A name of the artifact to collect. Returns: A list of results that artifact collection yielded. """ args = flows_pb2.ArtifactCollectorFlowArgs() args.artifact_list.append(artifact) args.apply_parsers = True try: ac = self._client.CreateFlow(name='ArtifactCollectorFlow', args=args) except api_errors.AccessForbiddenError as e: raise errors.ApprovalMissingError(self.id, e) _timeout.await_flow(ac) return [_.payload for _ in ac.ListResults()]
def yara(self, signature, pids=None, regex=None): """Scans processes using provided YARA rule. Args: signature: YARA rule to run. pids: List of pids of processes to scan. regex: A regex to match against the process name. Returns: A list of YARA matches. """ if pids is None: pids = [] args = flows_pb2.YaraProcessScanRequest() args.yara_signature = signature args.ignore_grr_process = False if regex is not None: args.process_regex = regex args.pids.extend(pids) try: yara = self._client.CreateFlow(name='YaraProcessScan', args=args) except api_errors.AccessForbiddenError as e: raise errors.ApprovalMissingError(self.id, e) _timeout.await_flow(yara) return [_.payload for _ in yara.ListResults()]
def fgrep(self, path: Text, literal: bytes) -> Sequence[jobs_pb2.BufferReference]: """Greps for given content on the specified path. Args: path: A path to a file to be searched. literal: A literal expression on search for. Returns: A list of buffer references to the matched content. """ args = flows_pb2.FileFinderArgs() args.paths.append(path) args.pathtype = self._path_type cond = args.conditions.add() cond.condition_type = \ flows_pb2.FileFinderCondition.Type.CONTENTS_LITERAL_MATCH cond.contents_literal_match.mode = \ flows_pb2.FileFinderContentsLiteralMatchCondition.Mode.ALL_HITS cond.contents_literal_match.literal = literal args.action.action_type = flows_pb2.FileFinderAction.Action.STAT try: ff = self._client.CreateFlow(name='FileFinder', args=args) except api_errors.AccessForbiddenError as e: raise errors.ApprovalMissingError(self.id, e) _timeout.await_flow(ff) results = [_first_match(result.payload) for result in ff.ListResults()] return representer.BufferReferenceList(results)
def ls(self, path, max_depth = 1): """Lists contents of a given directory. Args: path: A path to the directory to list the contents of. max_depth: Max depth of subdirectories to explore. If max_depth is >1, then the results will also include the contents of subdirectories (and sub-subdirectories and so on). Returns: A sequence of stat entries. """ if max_depth > 1: args = flows_pb2.RecursiveListDirectoryArgs() args.pathspec.path = path args.pathspec.pathtype = self._path_type args.max_depth = max_depth try: ls = self._client.CreateFlow(name='RecursiveListDirectory', args=args) except api_errors.AccessForbiddenError as e: raise errors.ApprovalMissingError(self.id, e) else: args = flows_pb2.ListDirectoryArgs() args.pathspec.path = path args.pathspec.pathtype = self._path_type try: ls = self._client.CreateFlow(name='ListDirectory', args=args) except api_errors.AccessForbiddenError as e: raise errors.ApprovalMissingError(self.id, e) _timeout.await_flow(ls) return representer.StatEntryList([_.payload for _ in ls.ListResults()])
def grep(self, path, pattern): """Greps for given content on the specified path. Args: path: A path to a file to be searched. pattern: A regular expression on search for. Returns: A list of buffer references to the matched content. """ args = flows_pb2.FileFinderArgs() args.paths.append(path) args.pathtype = self._path_type cond = args.conditions.add() cond.condition_type = \ flows_pb2.FileFinderCondition.Type.CONTENTS_REGEX_MATCH cond.contents_regex_match.mode = \ flows_pb2.FileFinderContentsRegexMatchCondition.ALL_HITS cond.contents_regex_match.regex = pattern args.action.action_type = flows_pb2.FileFinderAction.Action.STAT try: ff = self._client.CreateFlow(name='FileFinder', args=args) except api_errors.AccessForbiddenError as e: raise errors.ApprovalMissingError(self.id, e) _timeout.await_flow(ff) return representer.BufferReferenceList( [list(_.payload.matches)[0] for _ in ff.ListResults()])
def ps(self): """Returns a list of processes running on the client.""" args = flows_pb2.ListProcessesArgs() try: ps = self._client.CreateFlow(name='ListProcesses', args=args) except api_errors.AccessForbiddenError as e: raise errors.ApprovalMissingError(self.id, e) _timeout.await_flow(ps) return representer.ProcessList([_.payload for _ in ps.ListResults()])
def interrogate(self): """Grabs fresh metadata about the client. Returns: A client summary. """ try: interrogate = self._client.CreateFlow(name='Interrogate') except api_errors.AccessForbiddenError as e: raise errors.ApprovalMissingError(self.id, e) _timeout.await_flow(interrogate) self._summary = list(interrogate.ListResults())[0].payload return self._summary
def yara( self, signature: Text, pids: Optional[Sequence[int]] = None, regex: Optional[Text] = None, ) -> Sequence[flows_pb2.YaraProcessScanMatch]: """Scans processes using provided YARA rule. Args: signature: YARA rule to run. pids: List of pids of processes to scan. regex: A regex to match against the process name. Returns: A list of YARA matches. """ if pids is None: pids = [] args = flows_pb2.YaraProcessScanRequest() args.yara_signature = signature args.ignore_grr_process = False if regex is not None: args.process_regex = regex args.pids.extend(pids) try: yara = self._client.CreateFlow(name='YaraProcessScan', args=args) except api_errors.AccessForbiddenError as e: raise errors.ApprovalMissingError(self.id, e) _timeout.await_flow(yara) def yara_result( result: message.Message) -> flows_pb2.YaraProcessScanMatch: if not isinstance(result, flows_pb2.YaraProcessScanMatch): raise TypeError( f'Unexpected flow result type: {type(result)!r}') return result return [yara_result(result.payload) for result in yara.ListResults()]
def interrogate(self) -> jobs_pb2.ClientSummary: """Grabs fresh metadata about the client. Returns: A client summary. """ try: interrogate = self._client.CreateFlow(name='Interrogate') except api_errors.AccessForbiddenError as e: raise errors.ApprovalMissingError(self.id, e) _timeout.await_flow(interrogate) result = list(interrogate.ListResults())[0].payload if not isinstance(result, jobs_pb2.ClientSummary): raise TypeError(f'Unexpected flow result type: {type(result)!r}') self._summary = result return self._summary
def _collect_file(self, path: Text) -> None: """Save file from client to VFS. Args: path: A path to the file to collect. Returns: Nothing. """ args = flows_pb2.GetFileArgs() args.pathspec.path = path args.pathspec.pathtype = self._path_type try: gf = self._client.CreateFlow(name='GetFile', args=args) except api_errors.AccessForbiddenError as e: raise errors.ApprovalMissingError(self.id, e) _timeout.await_flow(gf)
def ps(self) -> Sequence[sysinfo_pb2.Process]: """Returns a list of processes running on the client.""" args = flows_pb2.ListProcessesArgs() try: ps = self._client.CreateFlow(name='ListProcesses', args=args) except api_errors.AccessForbiddenError as e: raise errors.ApprovalMissingError(self.id, e) _timeout.await_flow(ps) def process(result: message.Message) -> sysinfo_pb2.Process: if not isinstance(result, sysinfo_pb2.Process): raise TypeError(f'Unexpected flow result type: {type(result)!r}') return result results = [process(response.payload) for response in ps.ListResults()] return representer.ProcessList(results)
def glob(self, path): """Globs for files on the given client. Args: path: A glob expression (that may include `*` and `**`). Returns: A sequence of stat entries to the found files. """ args = flows_pb2.GlobArgs() args.paths.append(path) args.pathtype = self._path_type try: glob = self._client.CreateFlow(name='Glob', args=args) except api_errors.AccessForbiddenError as e: raise errors.ApprovalMissingError(self.id, e) _timeout.await_flow(glob) return representer.StatEntryList([_.payload for _ in glob.ListResults()])
def osquery(self, query, timeout=30000, ignore_stderr_errors=False): """Runs given query on the client. Args: query: An SQL query to run against osquery on the client. timeout: Query timeout in millis. ignore_stderr_errors: If true, will not break in case of stderr errors. Returns: An osquery table corresponding to the result of running the query. """ args = osquery_pb2.OsqueryArgs() args.query = query args.timeout_millis = timeout args.ignore_stderr_errors = ignore_stderr_errors try: oq = self._client.CreateFlow(name='OsqueryFlow', args=args) except api_errors.AccessForbiddenError as e: raise errors.ApprovalMissingError(self.id, e) _timeout.await_flow(oq) return list(oq.ListResults())[0].payload.table