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