@@ -19,12 +19,12 @@ def __init__(self):
1919 self .configpath = self .get_param ('config.velociraptor_client_config' , None , "File path missing!" )
2020 self .config = yaml .load (open (self .configpath ).read (), Loader = yaml .FullLoader )
2121 self .artifact = self .get_param ('config.velociraptor_artifact' , None , 'Artifact missing!' )
22- self .upload_flow_results = self .get_param ('config.upload_flow_results ' , None , 'Upload decision missing!' )
22+ self .artifact_args = self .get_param ('config.velociraptor_artifact_args ' , None )
2323 self .observable_type = self .get_param ('data.dataType' , None , "Data type is empty" )
2424 self .observable = self .get_param ('data.data' , None , 'Data missing!' )
25- self .thehive_url = self .get_param ('config.thehive_url ' , None , "TheHive URL missing!" )
26- self .thehive_apikey = self .get_param ('config.thehive_apikey ' , None , "TheHive API key missing!" )
27-
25+ self .max_wait = self .get_param ('config.query_max_duration ' , 600 )
26+ self .query = self .get_param ('config.velociraptor_query ' , None )
27+
2828 def run (self ):
2929 Responder .run (self )
3030 case_id = self .get_param ('data._parent' )
@@ -48,9 +48,10 @@ def run(self):
4848 self .report ({'message' : "Not a valid data type!" })
4949 return
5050
51- # Send initial request
51+ # Query to get client ID
5252 client_request = api_pb2 .VQLCollectorArgs (
53- max_wait = 1 ,
53+ # Setting static max_wait here, because it should not take as long as other queries
54+ max_wait = 60 ,
5455 Query = [api_pb2 .VQLRequest (
5556 Name = "TheHive-ClientQuery" ,
5657 VQL = client_query ,
@@ -64,121 +65,27 @@ def run(self):
6465 except :
6566 self .report ({'message' : 'Could not find a suitable client.' })
6667 pass
68+
69+ # Free-form query
70+ freeform_query = self .query
71+
72+ # Artifact query
73+ artifact_query = "LET collection <= collect_client(client_id='" + client_id + "',artifacts=['" + self .artifact + "'], spec=dict()) LET collection_completed <= SELECT * FROM watch_monitoring(artifact='System.Flow.Completion') WHERE FlowId = collection.flow_id LIMIT 1 SELECT * FROM source(client_id=collection.request.client_id, flow_id=collection.flow_id, artifact=collection_completed.Flow.artifacts_with_results[0])"
6774
68- # Define initial query
69- init_query = "SELECT collect_client(client_id='" + client_id + "',artifacts=['" + self .artifact + "']) FROM scope()"
75+
7076
71- # Send initial request
7277 request = api_pb2 .VQLCollectorArgs (
73- max_wait = 1 ,
78+ max_wait = self . max_wait ,
7479 Query = [api_pb2 .VQLRequest (
7580 Name = "TheHive-Query" ,
76- VQL = init_query ,
81+ VQL = artifact_query ,
7782 )])
7883
7984 for response in stub .Query (request ):
8085 try :
81- init_results = json .loads (response .Response )
82- flow = list (init_results [0 ].values ())[0 ]
83-
84- flow_id = str (flow ['flow_id' ])
85- # Define second query
86- flow_query = "SELECT * from flows(client_id='" + str (flow ['request' ]['client_id' ]) + "', flow_id='" + flow_id + "')"
87-
88- state = 0
89-
90- # Check to see if the flow has completed
91- while (state != 2 ):
92-
93- followup_request = api_pb2 .VQLCollectorArgs (
94- max_wait = 10 ,
95- Query = [api_pb2 .VQLRequest (
96- Name = "TheHive-QueryForFlow" ,
97- VQL = flow_query ,
98- )])
99-
100- for followup_response in stub .Query (followup_request ):
101- try :
102- flow_results = json .loads (followup_response .Response )
103- except :
104- pass
105- state = flow_results [0 ]['state' ]
106- global artifact_results
107- artifact_results = flow_results [0 ]['artifacts_with_results' ]
108- self .report ({'message' : state })
109- if state == 2 :
110- time .sleep (5 )
111- break
112-
113- # Grab the source from the artifact
114- source_results = []
115- for artifact in artifact_results :
116- source_query = "SELECT * from source(client_id='" + str (flow ['request' ]['client_id' ]) + "', flow_id='" + flow_id + "', artifact='" + artifact + "')"
117- source_request = api_pb2 .VQLCollectorArgs (
118- max_wait = 10 ,
119- Query = [api_pb2 .VQLRequest (
120- Name = "TheHive-SourceQuery" ,
121- VQL = source_query ,
122- )])
123- for source_response in stub .Query (source_request ):
124- try :
125- source_result = json .loads (source_response .Response )
126- source_results += source_result
127- except :
128- pass
129- self .report ({'message' : source_results })
130-
131- if self .upload_flow_results is True :
132- # Create flow download
133- vfs_query = "SELECT create_flow_download(client_id='" + str (flow ['request' ]['client_id' ]) + "', flow_id='" + str (flow ['flow_id' ]) + "', wait='true') as VFSPath from scope()"
134- vfs_request = api_pb2 .VQLCollectorArgs (
135- max_wait = 10 ,
136- Query = [api_pb2 .VQLRequest (
137- Name = "TheHive-VFSQuery" ,
138- VQL = vfs_query ,
139- )])
140- for vfs_response in stub .Query (vfs_request ):
141- try :
142- vfs_result = json .loads (vfs_response .Response )[0 ]['VFSPath' ]
143- except :
144- pass
145- # "Artifact" plugin.
146- offset = 0
147-
148- file_request = api_pb2 .VFSFileBuffer (
149- vfs_path = vfs_result ,
150- length = 10000 ,
151- offset = offset ,
152- )
153-
154- res = stub .VFSGetBuffer (file_request )
155-
156- if len (res .data ) == 0 :
157- break
158-
159-
160-
161- f = open ("/tmp/" + self .artifact + "_" + client_id + "_" + flow_id + "_" + case_id + ".zip" ,'wb' )
162- f .write (res .data )
163- offset += len (res .data )
164-
165- #Upload file to TheHive
166- api = TheHiveApi (self .thehive_url , self .thehive_apikey , cert = False )
167-
168- description = "Velociraptor flow for artifact" + self .artifact + "for client " + client_id + " via flow " + flow_id + "."
169- filepath = '/tmp/' + self .artifact + "_" + client_id + "_" + flow_id + "_" + case_id + ".zip"
170- file_observable = CaseObservable (dataType = 'file' ,
171- data = [filepath ],
172- tlp = self .get_param ('data.tlp' ),
173- ioc = True ,
174- tags = ['src:Velociraptor' , client_id ],
175- message = description
176- )
177-
178- response = api .create_case_observable (case_id , file_observable )
179- if response .status_code != 201 :
180- self .error ({'message' : str (response .status_code ) + " " + response .text })
181- os .remove (filepath )
86+ query_results = json .loads (response .Response )
87+ #flow=list(init_results[0].values())[0]
88+ self .report ({'message' : query_results })
18289 except :
18390 pass
18491 def operations (self , raw ):
0 commit comments