Server.Findflows

This artifact enables searching over client flow results with regex and returns a link to the Flow for followup.


name: Server.Findflows
author: Matt Green - @mgreen27
description: |
  This artifact enables searching over client flow results with regex
  and returns a link to the Flow for followup.

type: SERVER
parameters:
  - name: ClientData
    description: Glob for client data - may need to modify for non default installation
    default: /opt/velociraptor/clients/**
  - name: DateAfter
    type: timestamp
    description: "search for flow data after this date. YYYY-MM-DDTmm:hh:ssZ"
  - name: DateBefore
    type: timestamp
    description: "search for flow data before this date. YYYY-MM-DDTmm:hh:ssZ"
  - name: Workers
    type: int
    default: 100
    description: Number of concurrent workers
  - name: SearchRegex
    type: regex
    description: Second option Yara choice is a Velociraptor shorthand Yara rule
    default:
  - name: FindKeywordTemplate
    type: hidden
    default: |
        rule findregex {
            strings:
                $regex = /(REPLACEME)/i

            condition:
                $regex
        }

sources:
  - query: |
      -- create regex yara for search performance
      LET FinderYara = regex_replace(source=FindKeywordTemplate,re='REPLACEME',replace=SearchRegex)

      -- time testing
      LET time_test(stamp) =
            if(condition= DateBefore AND DateAfter,
                then= stamp < DateBefore AND stamp > DateAfter,
                else=
            if(condition=DateBefore,
                then= stamp < DateBefore,
                else=
            if(condition= DateAfter,
                then= stamp > DateAfter,
                else= True
            )))


      -- first find all matching glob
      LET files <= SELECT FinderYara,FullPath, Name, Size, Mtime, Atime, Ctime, Btime
        FROM glob(globs=ClientData,nosymlink='True')
        WHERE FullPath =~ '/F\\.[^\\./]+\\.json$'
          AND NOT IsDir AND NOT IsLink
          AND
             ( time_test(stamp=Mtime)
            OR time_test(stamp=Atime)
            OR time_test(stamp=Ctime) )


      -- scan files
      LET hits <= SELECT * FROM foreach(row=files,
            query={
                SELECT
                    FileName as FullPath,
                    File.Size AS Size,Mtime,
                    str(str=String.Data) AS HitContext
                FROM yara(rules=FinderYara,files=FullPath)
                LIMIT 1
            },workers=Workers)


      -- find configuration information
      LET find_hostname(ClientId) = SELECT os_info.hostname as Hostname FROM clients() WHERE client_id = ClientId
      

      -- enrich results
      LET flows = SELECT *,
            { SELECT HitContext FROM hits WHERE FullPath = FullPath GROUP BY lowcase(string=HitContext) } as HitContext, Mtime, FullPath,
            parse_string_with_regex(string=FullPath,regex='clients/(?P<ClientId>C\\.[^/]+)/artifacts').ClientId as ClientId,
            parse_string_with_regex(string=FullPath,regex='/(?P<FlowId>F\\.[^\\.]+)\\.json$').FlowId as FlowId
        FROM hits
        WHERE ClientId AND FlowId
        GROUP BY FullPath


      -- output rows
      SELECT
            find_hostname(ClientId=ClientId)[0].Hostname as Hostname,
            HitContext,
            Mtime as FlowModTime,
            '#/collected/' + ClientId + '/' + FlowId + '/notebook' as FlowNotebook,
            ClientId,FlowId
        FROM flows


column_types:
  - name: FlowModTime
    type: timestamp
  - name: FlowNotebook
    type: url